Split firebase_storage plugin into multiple files. (#550)

diff --git a/packages/firebase_storage/lib/firebase_storage.dart b/packages/firebase_storage/lib/firebase_storage.dart
index 726debc..88a7fe2 100755
--- a/packages/firebase_storage/lib/firebase_storage.dart
+++ b/packages/firebase_storage/lib/firebase_storage.dart
@@ -2,461 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+library firebase_storage;
+
 import 'dart:async';
 import 'dart:io';
 import 'dart:typed_data';
 
-import 'package:flutter/services.dart';
 import 'package:firebase_core/firebase_core.dart';
+import 'package:flutter/services.dart';
 
-/// FirebaseStorage is a service that supports uploading and downloading large
-/// objects to Google Cloud Storage.
-class FirebaseStorage {
-  static const MethodChannel channel =
-      const MethodChannel('plugins.flutter.io/firebase_storage');
-
-  /// Returns the [FirebaseStorage] instance, initialized with a custom
-  /// [FirebaseApp] if [app] is specified and a custom Google Cloud Storage
-  /// bucket if [storageBucket] is specified. Otherwise the instance will be
-  /// initialized with the default [FirebaseApp].
-  ///
-  /// The [FirebaseStorage] instance is a singleton for fixed [app] and
-  /// [storageBucket].
-  ///
-  /// The [storageBucket] argument is the gs:// url to the custom Firebase
-  /// Storage Bucket.
-  ///
-  /// The [app] argument is the custom [FirebaseApp].
-  FirebaseStorage({this.app, this.storageBucket});
-
-  static FirebaseStorage _instance = new FirebaseStorage();
-
-  /// The [FirebaseApp] instance to which this [FirebaseStorage] belongs.
-  ///
-  /// If null, the default [FirebaseApp] is used.
-  final FirebaseApp app;
-
-  /// The Google Cloud Storage bucket to which this [FirebaseStorage] belongs.
-  ///
-  /// If null, the storage bucket of the specified [FirebaseApp] is used.
-  final String storageBucket;
-
-  /// Returns the [FirebaseStorage] instance, initialized with the default
-  /// [FirebaseApp].
-  static FirebaseStorage get instance => _instance;
-
-  /// Creates a new [StorageReference] initialized at the root
-  /// Firebase Storage location.
-  StorageReference ref() => new StorageReference._(const <String>[], this);
-
-  Future<int> getMaxDownloadRetryTimeMillis() async {
-    return await channel.invokeMethod(
-        "FirebaseStorage#getMaxDownloadRetryTime", <String, dynamic>{
-      'app': app?.name,
-      'bucket': storageBucket,
-    });
-  }
-
-  Future<int> getMaxUploadRetryTimeMillis() async {
-    return await channel.invokeMethod(
-        "FirebaseStorage#getMaxUploadRetryTime", <String, dynamic>{
-      'app': app?.name,
-      'bucket': storageBucket,
-    });
-  }
-
-  Future<int> getMaxOperationRetryTimeMillis() async {
-    return await channel.invokeMethod(
-        "FirebaseStorage#getMaxOperationRetryTime", <String, dynamic>{
-      'app': app?.name,
-      'bucket': storageBucket,
-    });
-  }
-
-  Future<void> setMaxDownloadRetryTimeMillis(int time) {
-    return channel.invokeMethod(
-        "FirebaseStorage#setMaxDownloadRetryTime", <String, dynamic>{
-      'app': app?.name,
-      'bucket': storageBucket,
-      'time': time,
-    });
-  }
-
-  Future<void> setMaxUploadRetryTimeMillis(int time) {
-    return channel.invokeMethod(
-        "FirebaseStorage#setMaxUploadRetryTime", <String, dynamic>{
-      'app': app?.name,
-      'bucket': storageBucket,
-      'time': time,
-    });
-  }
-
-  Future<void> setMaxOperationRetryTimeMillis(int time) {
-    return channel.invokeMethod(
-        "FirebaseStorage#setMaxOperationRetryTime", <String, dynamic>{
-      'app': app?.name,
-      'bucket': storageBucket,
-      'time': time,
-    });
-  }
-}
-
-class StorageReference {
-  final FirebaseStorage _firebaseStorage;
-  const StorageReference._(this._pathComponents, this._firebaseStorage);
-  final List<String> _pathComponents;
-
-  /// Returns a new instance of [StorageReference] pointing to a child
-  /// location of the current reference.
-  StorageReference child(String path) {
-    final List<String> childPath = new List<String>.from(_pathComponents)
-      ..addAll(path.split("/"));
-    return new StorageReference._(childPath, _firebaseStorage);
-  }
-
-  /// Returns a new instance of [StorageReference] pointing to the parent
-  /// location or null if this instance references the root location.
-  StorageReference getParent() {
-    if (_pathComponents.isEmpty ||
-        _pathComponents.every((String e) => e.isEmpty)) {
-      return null;
-    }
-
-    final List<String> parentPath = new List<String>.from(_pathComponents);
-    // Trim for trailing empty path components that can
-    // come from trailing slashes in the path.
-    while (parentPath.last.isEmpty) {
-      parentPath.removeLast();
-    }
-    parentPath.removeLast();
-
-    return new StorageReference._(parentPath, _firebaseStorage);
-  }
-
-  /// Returns a new instance of [StorageReference] pointing to the root location.
-  StorageReference getRoot() {
-    return new StorageReference._(<String>[], _firebaseStorage);
-  }
-
-  /// Returns the [FirebaseStorage] service which created this reference.
-  FirebaseStorage getStorage() {
-    return _firebaseStorage;
-  }
-
-  /// This method is deprecated. Please use [putFile] instead.
-  ///
-  /// Asynchronously uploads a file to the currently specified
-  /// [StorageReference], with an optional [metadata].
-  @deprecated
-  StorageUploadTask put(File file, [StorageMetadata metadata]) {
-    return putFile(file, metadata);
-  }
-
-  /// Asynchronously uploads a file to the currently specified
-  /// [StorageReference], with an optional [metadata].
-  StorageUploadTask putFile(File file, [StorageMetadata metadata]) {
-    final StorageFileUploadTask task = new StorageFileUploadTask._(
-        file, _firebaseStorage, _pathComponents.join("/"), metadata);
-    task._start();
-    return task;
-  }
-
-  /// Asynchronously uploads byte data to the currently specified
-  /// [StorageReference], with an optional [metadata].
-  StorageUploadTask putData(Uint8List data, [StorageMetadata metadata]) {
-    final StorageUploadTask task = new StorageDataUploadTask._(
-        data, _firebaseStorage, _pathComponents.join("/"), metadata);
-    task._start();
-    return task;
-  }
-
-  /// Returns the Google Cloud Storage bucket that holds this object.
-  Future<String> getBucket() async {
-    return await FirebaseStorage.channel
-        .invokeMethod("StorageReference#getBucket", <String, String>{
-      'app': _firebaseStorage.app?.name,
-      'bucket': _firebaseStorage.storageBucket,
-      'path': _pathComponents.join("/"),
-    });
-  }
-
-  /// Returns the full path to this object, not including the Google Cloud
-  /// Storage bucket.
-  Future<String> getPath() async {
-    return await FirebaseStorage.channel
-        .invokeMethod("StorageReference#getPath", <String, String>{
-      'app': _firebaseStorage.app?.name,
-      'bucket': _firebaseStorage.storageBucket,
-      'path': _pathComponents.join("/"),
-    });
-  }
-
-  /// Returns the short name of this object.
-  Future<String> getName() async {
-    return await FirebaseStorage.channel
-        .invokeMethod("StorageReference#getName", <String, String>{
-      'app': _firebaseStorage.app?.name,
-      'bucket': _firebaseStorage.storageBucket,
-      'path': _pathComponents.join("/"),
-    });
-  }
-
-  /// Asynchronously downloads the object at the StorageReference to a list in memory.
-  /// A list of the provided max size will be allocated.
-  Future<Uint8List> getData(int maxSize) async {
-    return await FirebaseStorage.channel.invokeMethod(
-      "StorageReference#getData",
-      <String, dynamic>{
-        'app': _firebaseStorage.app?.name,
-        'bucket': _firebaseStorage.storageBucket,
-        'maxSize': maxSize,
-        'path': _pathComponents.join("/"),
-      },
-    );
-  }
-
-  /// Asynchronously downloads the object at this [StorageReference] to a
-  /// specified system file.
-  StorageFileDownloadTask writeToFile(File file) {
-    final StorageFileDownloadTask task = new StorageFileDownloadTask._(
-        _firebaseStorage, _pathComponents.join("/"), file);
-    task._start();
-    return task;
-  }
-
-  /// Asynchronously retrieves a long lived download URL with a revokable token.
-  /// This can be used to share the file with others, but can be revoked by a
-  /// developer in the Firebase Console if desired.
-  Future<dynamic> getDownloadURL() async {
-    return await FirebaseStorage.channel
-        .invokeMethod("StorageReference#getDownloadUrl", <String, String>{
-      'app': _firebaseStorage.app?.name,
-      'bucket': _firebaseStorage.storageBucket,
-      'path': _pathComponents.join("/"),
-    });
-  }
-
-  Future<void> delete() {
-    return FirebaseStorage.channel
-        .invokeMethod("StorageReference#delete", <String, String>{
-      'app': _firebaseStorage.app?.name,
-      'bucket': _firebaseStorage.storageBucket,
-      'path': _pathComponents.join("/")
-    });
-  }
-
-  /// Retrieves metadata associated with an object at this [StorageReference].
-  Future<StorageMetadata> getMetadata() async {
-    return new StorageMetadata._fromMap(await FirebaseStorage.channel
-        .invokeMethod("StorageReference#getMetadata", <String, String>{
-      'app': _firebaseStorage.app?.name,
-      'bucket': _firebaseStorage.storageBucket,
-      'path': _pathComponents.join("/"),
-    }));
-  }
-
-  /// Updates the metadata associated with this [StorageReference].
-  ///
-  /// Returns a [Future] that will complete to the updated [StorageMetadata].
-  ///
-  /// This method ignores fields of [metadata] that cannot be set by the public
-  /// [StorageMetadata] constructor. Writable metadata properties can be deleted
-  /// by passing the empty string.
-  Future<StorageMetadata> updateMetadata(StorageMetadata metadata) async {
-    return new StorageMetadata._fromMap(await FirebaseStorage.channel
-        .invokeMethod("StorageReference#updateMetadata", <String, dynamic>{
-      'app': _firebaseStorage.app?.name,
-      'bucket': _firebaseStorage.storageBucket,
-      'path': _pathComponents.join("/"),
-      'metadata': metadata == null ? null : _buildMetadataUploadMap(metadata),
-    }));
-  }
-
-  String get path => _pathComponents.join('/');
-}
-
-/// Metadata for a [StorageReference]. Metadata stores default attributes such as
-/// size and content type.
-class StorageMetadata {
-  const StorageMetadata({
-    this.cacheControl,
-    this.contentDisposition,
-    this.contentEncoding,
-    this.contentLanguage,
-    this.contentType,
-  })  : bucket = null,
-        generation = null,
-        metadataGeneration = null,
-        path = null,
-        name = null,
-        sizeBytes = null,
-        creationTimeMillis = null,
-        updatedTimeMillis = null,
-        md5Hash = null;
-
-  StorageMetadata._fromMap(Map<dynamic, dynamic> map)
-      : bucket = map['bucket'],
-        generation = map['generation'],
-        metadataGeneration = map['metadataGeneration'],
-        path = map['path'],
-        name = map['name'],
-        sizeBytes = map['sizeBytes'],
-        creationTimeMillis = map['creationTimeMillis'],
-        updatedTimeMillis = map['updatedTimeMillis'],
-        md5Hash = map['md5Hash'],
-        cacheControl = map['cacheControl'],
-        contentDisposition = map['contentDisposition'],
-        contentLanguage = map['contentLanguage'],
-        contentType = map['contentType'],
-        contentEncoding = map['contentEncoding'];
-
-  /// The owning Google Cloud Storage bucket for the [StorageReference].
-  final String bucket;
-
-  /// A version String indicating what version of the [StorageReference].
-  final String generation;
-
-  /// A version String indicating the version of this [StorageMetadata].
-  final String metadataGeneration;
-
-  /// The path of the [StorageReference] object.
-  final String path;
-
-  /// A simple name of the [StorageReference] object.
-  final String name;
-
-  /// The stored Size in bytes of the [StorageReference] object.
-  final int sizeBytes;
-
-  /// The time the [StorageReference] was created in milliseconds since the epoch.
-  final int creationTimeMillis;
-
-  /// The time the [StorageReference] was last updated in milliseconds since the epoch.
-  final int updatedTimeMillis;
-
-  /// The MD5Hash of the [StorageReference] object.
-  final String md5Hash;
-
-  /// The Cache Control setting of the [StorageReference].
-  final String cacheControl;
-
-  /// The content disposition of the [StorageReference].
-  final String contentDisposition;
-
-  /// The content encoding for the [StorageReference].
-  final String contentEncoding;
-
-  /// The content language for the StorageReference, specified as a 2-letter
-  /// lowercase language code defined by ISO 639-1.
-  final String contentLanguage;
-
-  /// The content type (MIME type) of the [StorageReference].
-  final String contentType;
-}
-
-class StorageFileDownloadTask {
-  final FirebaseStorage _firebaseStorage;
-  final String _path;
-  final File _file;
-
-  StorageFileDownloadTask._(this._firebaseStorage, this._path, this._file);
-
-  Future<void> _start() async {
-    final int totalByteCount = await FirebaseStorage.channel.invokeMethod(
-      "StorageReference#writeToFile",
-      <String, dynamic>{
-        'app': _firebaseStorage.app?.name,
-        'bucket': _firebaseStorage.storageBucket,
-        'filePath': _file.absolute.path,
-        'path': _path,
-      },
-    );
-    _completer
-        .complete(new FileDownloadTaskSnapshot(totalByteCount: totalByteCount));
-  }
-
-  Completer<FileDownloadTaskSnapshot> _completer =
-      new Completer<FileDownloadTaskSnapshot>();
-  Future<FileDownloadTaskSnapshot> get future => _completer.future;
-}
-
-abstract class StorageUploadTask {
-  final FirebaseStorage _firebaseStorage;
-  final String _path;
-  final StorageMetadata _metadata;
-
-  StorageUploadTask._(this._firebaseStorage, this._path, this._metadata);
-  Future<void> _start();
-
-  Completer<UploadTaskSnapshot> _completer =
-      new Completer<UploadTaskSnapshot>();
-  Future<UploadTaskSnapshot> get future => _completer.future;
-}
-
-class StorageFileUploadTask extends StorageUploadTask {
-  final File _file;
-  StorageFileUploadTask._(this._file, FirebaseStorage firebaseStorage,
-      String path, StorageMetadata metadata)
-      : super._(firebaseStorage, path, metadata);
-
-  @override
-  Future<void> _start() async {
-    final String downloadUrl = await FirebaseStorage.channel.invokeMethod(
-      'StorageReference#putFile',
-      <String, dynamic>{
-        'app': _firebaseStorage.app?.name,
-        'bucket': _firebaseStorage.storageBucket,
-        'filename': _file.absolute.path,
-        'path': _path,
-        'metadata':
-            _metadata == null ? null : _buildMetadataUploadMap(_metadata),
-      },
-    );
-    _completer
-        .complete(new UploadTaskSnapshot(downloadUrl: Uri.parse(downloadUrl)));
-  }
-}
-
-class StorageDataUploadTask extends StorageUploadTask {
-  final Uint8List _bytes;
-  StorageDataUploadTask._(this._bytes, FirebaseStorage firebaseStorage,
-      String path, StorageMetadata metadata)
-      : super._(firebaseStorage, path, metadata);
-
-  @override
-  Future<void> _start() async {
-    final String downloadUrl = await FirebaseStorage.channel.invokeMethod(
-      'StorageReference#putData',
-      <String, dynamic>{
-        'app': _firebaseStorage.app?.name,
-        'bucket': _firebaseStorage.storageBucket,
-        'data': _bytes,
-        'path': _path,
-        'metadata':
-            _metadata == null ? null : _buildMetadataUploadMap(_metadata),
-      },
-    );
-    _completer
-        .complete(new UploadTaskSnapshot(downloadUrl: Uri.parse(downloadUrl)));
-  }
-}
-
-Map<String, dynamic> _buildMetadataUploadMap(StorageMetadata metadata) {
-  return <String, dynamic>{
-    'cacheControl': metadata.cacheControl,
-    'contentDisposition': metadata.contentDisposition,
-    'contentLanguage': metadata.contentLanguage,
-    'contentType': metadata.contentType,
-    'contentEncoding': metadata.contentEncoding,
-  };
-}
-
-class UploadTaskSnapshot {
-  UploadTaskSnapshot({this.downloadUrl});
-  final Uri downloadUrl;
-}
-
-class FileDownloadTaskSnapshot {
-  FileDownloadTaskSnapshot({this.totalByteCount});
-  final int totalByteCount;
-}
+part 'src/firebase_storage.dart';
+part 'src/storage_metadata.dart';
+part 'src/storage_reference.dart';
+part 'src/upload_task.dart';
diff --git a/packages/firebase_storage/lib/src/firebase_storage.dart b/packages/firebase_storage/lib/src/firebase_storage.dart
new file mode 100644
index 0000000..a4a5df7
--- /dev/null
+++ b/packages/firebase_storage/lib/src/firebase_storage.dart
@@ -0,0 +1,128 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+part of firebase_storage;
+
+/// FirebaseStorage is a service that supports uploading and downloading large
+/// objects to Google Cloud Storage.
+class FirebaseStorage {
+  static const MethodChannel channel =
+      const MethodChannel('plugins.flutter.io/firebase_storage');
+
+  /// Returns the [FirebaseStorage] instance, initialized with a custom
+  /// [FirebaseApp] if [app] is specified and a custom Google Cloud Storage
+  /// bucket if [storageBucket] is specified. Otherwise the instance will be
+  /// initialized with the default [FirebaseApp].
+  ///
+  /// The [FirebaseStorage] instance is a singleton for fixed [app] and
+  /// [storageBucket].
+  ///
+  /// The [storageBucket] argument is the gs:// url to the custom Firebase
+  /// Storage Bucket.
+  ///
+  /// The [app] argument is the custom [FirebaseApp].
+  FirebaseStorage({this.app, this.storageBucket});
+
+  static FirebaseStorage _instance = new FirebaseStorage();
+
+  /// The [FirebaseApp] instance to which this [FirebaseStorage] belongs.
+  ///
+  /// If null, the default [FirebaseApp] is used.
+  final FirebaseApp app;
+
+  /// The Google Cloud Storage bucket to which this [FirebaseStorage] belongs.
+  ///
+  /// If null, the storage bucket of the specified [FirebaseApp] is used.
+  final String storageBucket;
+
+  /// Returns the [FirebaseStorage] instance, initialized with the default
+  /// [FirebaseApp].
+  static FirebaseStorage get instance => _instance;
+
+  /// Creates a new [StorageReference] initialized at the root
+  /// Firebase Storage location.
+  StorageReference ref() => new StorageReference._(const <String>[], this);
+
+  Future<int> getMaxDownloadRetryTimeMillis() async {
+    return await channel.invokeMethod(
+        "FirebaseStorage#getMaxDownloadRetryTime", <String, dynamic>{
+      'app': app?.name,
+      'bucket': storageBucket,
+    });
+  }
+
+  Future<int> getMaxUploadRetryTimeMillis() async {
+    return await channel.invokeMethod(
+        "FirebaseStorage#getMaxUploadRetryTime", <String, dynamic>{
+      'app': app?.name,
+      'bucket': storageBucket,
+    });
+  }
+
+  Future<int> getMaxOperationRetryTimeMillis() async {
+    return await channel.invokeMethod(
+        "FirebaseStorage#getMaxOperationRetryTime", <String, dynamic>{
+      'app': app?.name,
+      'bucket': storageBucket,
+    });
+  }
+
+  Future<void> setMaxDownloadRetryTimeMillis(int time) {
+    return channel.invokeMethod(
+        "FirebaseStorage#setMaxDownloadRetryTime", <String, dynamic>{
+      'app': app?.name,
+      'bucket': storageBucket,
+      'time': time,
+    });
+  }
+
+  Future<void> setMaxUploadRetryTimeMillis(int time) {
+    return channel.invokeMethod(
+        "FirebaseStorage#setMaxUploadRetryTime", <String, dynamic>{
+      'app': app?.name,
+      'bucket': storageBucket,
+      'time': time,
+    });
+  }
+
+  Future<void> setMaxOperationRetryTimeMillis(int time) {
+    return channel.invokeMethod(
+        "FirebaseStorage#setMaxOperationRetryTime", <String, dynamic>{
+      'app': app?.name,
+      'bucket': storageBucket,
+      'time': time,
+    });
+  }
+}
+
+class StorageFileDownloadTask {
+  final FirebaseStorage _firebaseStorage;
+  final String _path;
+  final File _file;
+
+  StorageFileDownloadTask._(this._firebaseStorage, this._path, this._file);
+
+  Future<void> _start() async {
+    final int totalByteCount = await FirebaseStorage.channel.invokeMethod(
+      "StorageReference#writeToFile",
+      <String, dynamic>{
+        'app': _firebaseStorage.app?.name,
+        'bucket': _firebaseStorage.storageBucket,
+        'filePath': _file.absolute.path,
+        'path': _path,
+      },
+    );
+    _completer
+        .complete(new FileDownloadTaskSnapshot(totalByteCount: totalByteCount));
+  }
+
+  Completer<FileDownloadTaskSnapshot> _completer =
+      new Completer<FileDownloadTaskSnapshot>();
+  Future<FileDownloadTaskSnapshot> get future => _completer.future;
+}
+
+class FileDownloadTaskSnapshot {
+  FileDownloadTaskSnapshot({this.totalByteCount});
+  final int totalByteCount;
+}
diff --git a/packages/firebase_storage/lib/src/storage_metadata.dart b/packages/firebase_storage/lib/src/storage_metadata.dart
new file mode 100644
index 0000000..54f7e59
--- /dev/null
+++ b/packages/firebase_storage/lib/src/storage_metadata.dart
@@ -0,0 +1,84 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+part of firebase_storage;
+
+/// Metadata for a [StorageReference]. Metadata stores default attributes such as
+/// size and content type.
+class StorageMetadata {
+  const StorageMetadata({
+    this.cacheControl,
+    this.contentDisposition,
+    this.contentEncoding,
+    this.contentLanguage,
+    this.contentType,
+  })  : bucket = null,
+        generation = null,
+        metadataGeneration = null,
+        path = null,
+        name = null,
+        sizeBytes = null,
+        creationTimeMillis = null,
+        updatedTimeMillis = null,
+        md5Hash = null;
+
+  StorageMetadata._fromMap(Map<dynamic, dynamic> map)
+      : bucket = map['bucket'],
+        generation = map['generation'],
+        metadataGeneration = map['metadataGeneration'],
+        path = map['path'],
+        name = map['name'],
+        sizeBytes = map['sizeBytes'],
+        creationTimeMillis = map['creationTimeMillis'],
+        updatedTimeMillis = map['updatedTimeMillis'],
+        md5Hash = map['md5Hash'],
+        cacheControl = map['cacheControl'],
+        contentDisposition = map['contentDisposition'],
+        contentLanguage = map['contentLanguage'],
+        contentType = map['contentType'],
+        contentEncoding = map['contentEncoding'];
+
+  /// The owning Google Cloud Storage bucket for the [StorageReference].
+  final String bucket;
+
+  /// A version String indicating what version of the [StorageReference].
+  final String generation;
+
+  /// A version String indicating the version of this [StorageMetadata].
+  final String metadataGeneration;
+
+  /// The path of the [StorageReference] object.
+  final String path;
+
+  /// A simple name of the [StorageReference] object.
+  final String name;
+
+  /// The stored Size in bytes of the [StorageReference] object.
+  final int sizeBytes;
+
+  /// The time the [StorageReference] was created in milliseconds since the epoch.
+  final int creationTimeMillis;
+
+  /// The time the [StorageReference] was last updated in milliseconds since the epoch.
+  final int updatedTimeMillis;
+
+  /// The MD5Hash of the [StorageReference] object.
+  final String md5Hash;
+
+  /// The Cache Control setting of the [StorageReference].
+  final String cacheControl;
+
+  /// The content disposition of the [StorageReference].
+  final String contentDisposition;
+
+  /// The content encoding for the [StorageReference].
+  final String contentEncoding;
+
+  /// The content language for the StorageReference, specified as a 2-letter
+  /// lowercase language code defined by ISO 639-1.
+  final String contentLanguage;
+
+  /// The content type (MIME type) of the [StorageReference].
+  final String contentType;
+}
diff --git a/packages/firebase_storage/lib/src/storage_reference.dart b/packages/firebase_storage/lib/src/storage_reference.dart
new file mode 100644
index 0000000..a5902f8
--- /dev/null
+++ b/packages/firebase_storage/lib/src/storage_reference.dart
@@ -0,0 +1,179 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+part of firebase_storage;
+
+class StorageReference {
+  final FirebaseStorage _firebaseStorage;
+  const StorageReference._(this._pathComponents, this._firebaseStorage);
+  final List<String> _pathComponents;
+
+  /// Returns a new instance of [StorageReference] pointing to a child
+  /// location of the current reference.
+  StorageReference child(String path) {
+    final List<String> childPath = new List<String>.from(_pathComponents)
+      ..addAll(path.split("/"));
+    return new StorageReference._(childPath, _firebaseStorage);
+  }
+
+  /// Returns a new instance of [StorageReference] pointing to the parent
+  /// location or null if this instance references the root location.
+  StorageReference getParent() {
+    if (_pathComponents.isEmpty ||
+        _pathComponents.every((String e) => e.isEmpty)) {
+      return null;
+    }
+
+    final List<String> parentPath = new List<String>.from(_pathComponents);
+    // Trim for trailing empty path components that can
+    // come from trailing slashes in the path.
+    while (parentPath.last.isEmpty) {
+      parentPath.removeLast();
+    }
+    parentPath.removeLast();
+
+    return new StorageReference._(parentPath, _firebaseStorage);
+  }
+
+  /// Returns a new instance of [StorageReference] pointing to the root location.
+  StorageReference getRoot() {
+    return new StorageReference._(<String>[], _firebaseStorage);
+  }
+
+  /// Returns the [FirebaseStorage] service which created this reference.
+  FirebaseStorage getStorage() {
+    return _firebaseStorage;
+  }
+
+  /// This method is deprecated. Please use [putFile] instead.
+  ///
+  /// Asynchronously uploads a file to the currently specified
+  /// [StorageReference], with an optional [metadata].
+  @deprecated
+  StorageUploadTask put(File file, [StorageMetadata metadata]) {
+    return putFile(file, metadata);
+  }
+
+  /// Asynchronously uploads a file to the currently specified
+  /// [StorageReference], with an optional [metadata].
+  StorageUploadTask putFile(File file, [StorageMetadata metadata]) {
+    final StorageFileUploadTask task = new StorageFileUploadTask._(
+        file, _firebaseStorage, _pathComponents.join("/"), metadata);
+    task._start();
+    return task;
+  }
+
+  /// Asynchronously uploads byte data to the currently specified
+  /// [StorageReference], with an optional [metadata].
+  StorageUploadTask putData(Uint8List data, [StorageMetadata metadata]) {
+    final StorageUploadTask task = new StorageDataUploadTask._(
+        data, _firebaseStorage, _pathComponents.join("/"), metadata);
+    task._start();
+    return task;
+  }
+
+  /// Returns the Google Cloud Storage bucket that holds this object.
+  Future<String> getBucket() async {
+    return await FirebaseStorage.channel
+        .invokeMethod("StorageReference#getBucket", <String, String>{
+      'app': _firebaseStorage.app?.name,
+      'bucket': _firebaseStorage.storageBucket,
+      'path': _pathComponents.join("/"),
+    });
+  }
+
+  /// Returns the full path to this object, not including the Google Cloud
+  /// Storage bucket.
+  Future<String> getPath() async {
+    return await FirebaseStorage.channel
+        .invokeMethod("StorageReference#getPath", <String, String>{
+      'app': _firebaseStorage.app?.name,
+      'bucket': _firebaseStorage.storageBucket,
+      'path': _pathComponents.join("/"),
+    });
+  }
+
+  /// Returns the short name of this object.
+  Future<String> getName() async {
+    return await FirebaseStorage.channel
+        .invokeMethod("StorageReference#getName", <String, String>{
+      'app': _firebaseStorage.app?.name,
+      'bucket': _firebaseStorage.storageBucket,
+      'path': _pathComponents.join("/"),
+    });
+  }
+
+  /// Asynchronously downloads the object at the StorageReference to a list in memory.
+  /// A list of the provided max size will be allocated.
+  Future<Uint8List> getData(int maxSize) async {
+    return await FirebaseStorage.channel.invokeMethod(
+      "StorageReference#getData",
+      <String, dynamic>{
+        'app': _firebaseStorage.app?.name,
+        'bucket': _firebaseStorage.storageBucket,
+        'maxSize': maxSize,
+        'path': _pathComponents.join("/"),
+      },
+    );
+  }
+
+  /// Asynchronously downloads the object at this [StorageReference] to a
+  /// specified system file.
+  StorageFileDownloadTask writeToFile(File file) {
+    final StorageFileDownloadTask task = new StorageFileDownloadTask._(
+        _firebaseStorage, _pathComponents.join("/"), file);
+    task._start();
+    return task;
+  }
+
+  /// Asynchronously retrieves a long lived download URL with a revokable token.
+  /// This can be used to share the file with others, but can be revoked by a
+  /// developer in the Firebase Console if desired.
+  Future<dynamic> getDownloadURL() async {
+    return await FirebaseStorage.channel
+        .invokeMethod("StorageReference#getDownloadUrl", <String, String>{
+      'app': _firebaseStorage.app?.name,
+      'bucket': _firebaseStorage.storageBucket,
+      'path': _pathComponents.join("/"),
+    });
+  }
+
+  Future<void> delete() {
+    return FirebaseStorage.channel
+        .invokeMethod("StorageReference#delete", <String, String>{
+      'app': _firebaseStorage.app?.name,
+      'bucket': _firebaseStorage.storageBucket,
+      'path': _pathComponents.join("/")
+    });
+  }
+
+  /// Retrieves metadata associated with an object at this [StorageReference].
+  Future<StorageMetadata> getMetadata() async {
+    return new StorageMetadata._fromMap(await FirebaseStorage.channel
+        .invokeMethod("StorageReference#getMetadata", <String, String>{
+      'app': _firebaseStorage.app?.name,
+      'bucket': _firebaseStorage.storageBucket,
+      'path': _pathComponents.join("/"),
+    }));
+  }
+
+  /// Updates the metadata associated with this [StorageReference].
+  ///
+  /// Returns a [Future] that will complete to the updated [StorageMetadata].
+  ///
+  /// This method ignores fields of [metadata] that cannot be set by the public
+  /// [StorageMetadata] constructor. Writable metadata properties can be deleted
+  /// by passing the empty string.
+  Future<StorageMetadata> updateMetadata(StorageMetadata metadata) async {
+    return new StorageMetadata._fromMap(await FirebaseStorage.channel
+        .invokeMethod("StorageReference#updateMetadata", <String, dynamic>{
+      'app': _firebaseStorage.app?.name,
+      'bucket': _firebaseStorage.storageBucket,
+      'path': _pathComponents.join("/"),
+      'metadata': metadata == null ? null : _buildMetadataUploadMap(metadata),
+    }));
+  }
+
+  String get path => _pathComponents.join('/');
+}
diff --git a/packages/firebase_storage/lib/src/upload_task.dart b/packages/firebase_storage/lib/src/upload_task.dart
new file mode 100644
index 0000000..7ec79c2
--- /dev/null
+++ b/packages/firebase_storage/lib/src/upload_task.dart
@@ -0,0 +1,81 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+part of firebase_storage;
+
+abstract class StorageUploadTask {
+  final FirebaseStorage _firebaseStorage;
+  final String _path;
+  final StorageMetadata _metadata;
+
+  StorageUploadTask._(this._firebaseStorage, this._path, this._metadata);
+  Future<void> _start();
+
+  Completer<UploadTaskSnapshot> _completer =
+      new Completer<UploadTaskSnapshot>();
+  Future<UploadTaskSnapshot> get future => _completer.future;
+}
+
+class StorageFileUploadTask extends StorageUploadTask {
+  final File _file;
+  StorageFileUploadTask._(this._file, FirebaseStorage firebaseStorage,
+      String path, StorageMetadata metadata)
+      : super._(firebaseStorage, path, metadata);
+
+  @override
+  Future<void> _start() async {
+    final String downloadUrl = await FirebaseStorage.channel.invokeMethod(
+      'StorageReference#putFile',
+      <String, dynamic>{
+        'app': _firebaseStorage.app?.name,
+        'bucket': _firebaseStorage.storageBucket,
+        'filename': _file.absolute.path,
+        'path': _path,
+        'metadata':
+            _metadata == null ? null : _buildMetadataUploadMap(_metadata),
+      },
+    );
+    _completer
+        .complete(new UploadTaskSnapshot(downloadUrl: Uri.parse(downloadUrl)));
+  }
+}
+
+class StorageDataUploadTask extends StorageUploadTask {
+  final Uint8List _bytes;
+  StorageDataUploadTask._(this._bytes, FirebaseStorage firebaseStorage,
+      String path, StorageMetadata metadata)
+      : super._(firebaseStorage, path, metadata);
+
+  @override
+  Future<void> _start() async {
+    final String downloadUrl = await FirebaseStorage.channel.invokeMethod(
+      'StorageReference#putData',
+      <String, dynamic>{
+        'app': _firebaseStorage.app?.name,
+        'bucket': _firebaseStorage.storageBucket,
+        'data': _bytes,
+        'path': _path,
+        'metadata':
+            _metadata == null ? null : _buildMetadataUploadMap(_metadata),
+      },
+    );
+    _completer
+        .complete(new UploadTaskSnapshot(downloadUrl: Uri.parse(downloadUrl)));
+  }
+}
+
+Map<String, dynamic> _buildMetadataUploadMap(StorageMetadata metadata) {
+  return <String, dynamic>{
+    'cacheControl': metadata.cacheControl,
+    'contentDisposition': metadata.contentDisposition,
+    'contentLanguage': metadata.contentLanguage,
+    'contentType': metadata.contentType,
+    'contentEncoding': metadata.contentEncoding,
+  };
+}
+
+class UploadTaskSnapshot {
+  UploadTaskSnapshot({this.downloadUrl});
+  final Uri downloadUrl;
+}