pkg/mime: layout as mini-libraries
Update version for publishing
Updated max unittest dependency version
R=ajohnsen@google.com
Review URL: https://codereview.chromium.org//272353002
git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/mime@36115 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/lib/mime.dart b/lib/mime.dart
index d1372d4..11b2ca9 100644
--- a/lib/mime.dart
+++ b/lib/mime.dart
@@ -14,11 +14,5 @@
*/
library mime;
-import 'dart:async';
-import 'dart:convert';
-import 'dart:typed_data';
-
-part 'src/mime_type.dart';
-part 'src/extension_map.dart';
-part 'src/magic_number.dart';
-part 'src/mime_multipart_transformer.dart';
+export 'src/mime_multipart_transformer.dart';
+export 'src/mime_type.dart';
diff --git a/lib/src/extension_map.dart b/lib/src/default_extension_map.dart
similarity index 99%
rename from lib/src/extension_map.dart
rename to lib/src/default_extension_map.dart
index 745556b..7e74648 100644
--- a/lib/src/extension_map.dart
+++ b/lib/src/default_extension_map.dart
@@ -2,11 +2,10 @@
// for details. 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 mime;
-
+library mime.extension_map;
// TODO(ajohnsen): Use sorted list and binary search?
-const Map<String, String> _DEFAULT_EXTENSION_MAP = const <String, String>{
+const Map<String, String> DEFAULT_EXTENSION_MAP = const <String, String>{
'123':'application/vnd.lotus-1-2-3',
'3dml':'text/vnd.in3d.3dml',
'3ds':'image/x-3ds',
diff --git a/lib/src/magic_number.dart b/lib/src/magic_number.dart
index 1229b6d..6c554aa 100644
--- a/lib/src/magic_number.dart
+++ b/lib/src/magic_number.dart
@@ -2,15 +2,14 @@
// for details. 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 mime;
+library mime.magic_number;
-
-class _MagicNumber {
+class MagicNumber {
final String mimeType;
final List<int> numbers;
final List<int> mask;
- const _MagicNumber(this.mimeType, this.numbers, {this.mask});
+ const MagicNumber(this.mimeType, this.numbers, {this.mask});
bool matches(List<int> header) {
if (header.length < numbers.length) return false;
@@ -28,19 +27,17 @@
}
-const int _DEFAULT_MAGIC_NUMBERS_MAX_LENGTH = 16;
-
-const List<_MagicNumber> _DEFAULT_MAGIC_NUMBERS = const [
- const _MagicNumber('application/pdf', const [0x25, 0x50, 0x44, 0x46]),
- const _MagicNumber('application/postscript', const [0x25, 0x51]),
- const _MagicNumber('image/gif', const [0x47, 0x49, 0x46, 0x38, 0x37, 0x61]),
- const _MagicNumber('image/gif', const [0x47, 0x49, 0x46, 0x38, 0x39, 0x61]),
- const _MagicNumber('image/jpeg', const [0xFF, 0xD8]),
- const _MagicNumber('image/png',
+const List<MagicNumber> DEFAULT_MAGIC_NUMBERS = const [
+ const MagicNumber('application/pdf', const [0x25, 0x50, 0x44, 0x46]),
+ const MagicNumber('application/postscript', const [0x25, 0x51]),
+ const MagicNumber('image/gif', const [0x47, 0x49, 0x46, 0x38, 0x37, 0x61]),
+ const MagicNumber('image/gif', const [0x47, 0x49, 0x46, 0x38, 0x39, 0x61]),
+ const MagicNumber('image/jpeg', const [0xFF, 0xD8]),
+ const MagicNumber('image/png',
const [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]),
- const _MagicNumber('image/tiff', const [0x49, 0x49, 0x2A, 0x00]),
- const _MagicNumber('image/tiff', const [0x4D, 0x4D, 0x00, 0x2A]),
- const _MagicNumber(
+ const MagicNumber('image/tiff', const [0x49, 0x49, 0x2A, 0x00]),
+ const MagicNumber('image/tiff', const [0x4D, 0x4D, 0x00, 0x2A]),
+ const MagicNumber(
'video/mp4',
const [0x00, 0x00, 0x00, 0x00, 0x66, 0x74,
0x79, 0x70, 0x33, 0x67, 0x70, 0x35],
diff --git a/lib/src/mime_multipart_transformer.dart b/lib/src/mime_multipart_transformer.dart
index a35b491..75d10ff 100644
--- a/lib/src/mime_multipart_transformer.dart
+++ b/lib/src/mime_multipart_transformer.dart
@@ -2,8 +2,11 @@
// for details. 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 mime;
+library mime.multipart_transformer;
+import 'dart:async';
+import 'dart:convert';
+import 'dart:typed_data';
/**
* A Mime Multipart class representing each part parsed by
@@ -30,12 +33,6 @@
}
}
-class _Const {
- // Bytes for '()<>@,;:\\"/[]?={} \t'.
- static const SEPARATORS = const [40, 41, 60, 62, 64, 44, 59, 58, 92, 34, 47,
- 91, 93, 63, 61, 123, 125, 32, 9];
-}
-
class _CharCode {
static const int HT = 9;
static const int LF = 10;
@@ -71,6 +68,10 @@
static const int _DONE = 14;
static const int _FAILURE = 15;
+ // Bytes for '()<>@,;:\\"/[]?={} \t'.
+ static const _SEPARATORS = const [40, 41, 60, 62, 64, 44, 59, 58, 92, 34, 47,
+ 91, 93, 63, 61, 123, 125, 32, 9];
+
StreamController _controller;
StreamSubscription _subscription;
@@ -387,7 +388,7 @@
}
bool _isTokenChar(int byte) {
- return byte > 31 && byte < 128 && _Const.SEPARATORS.indexOf(byte) == -1;
+ return byte > 31 && byte < 128 && _SEPARATORS.indexOf(byte) == -1;
}
int _toLowerCase(int byte) {
@@ -412,7 +413,9 @@
class MimeMultipartException implements Exception {
- const MimeMultipartException([String this.message = ""]);
- String toString() => "MimeMultipartException: $message";
final String message;
+
+ const MimeMultipartException([String this.message = ""]);
+
+ String toString() => "MimeMultipartException: $message";
}
diff --git a/lib/src/mime_type.dart b/lib/src/mime_type.dart
index c9daa2b..ca4d6c5 100644
--- a/lib/src/mime_type.dart
+++ b/lib/src/mime_type.dart
@@ -2,15 +2,18 @@
// for details. 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 mime;
+library mime.mime_type;
+import 'default_extension_map.dart';
+import 'magic_number.dart';
final MimeTypeResolver _globalResolver = new MimeTypeResolver();
/**
* The maximum number of bytes needed, to match all default magic-numbers.
*/
-int get defaultMagicNumbersMaxLength => _DEFAULT_MAGIC_NUMBERS_MAX_LENGTH;
+// NOTE: this is not formatted AS_A_CONST to avoid a breaking change
+const int defaultMagicNumbersMaxLength = 12;
/**
* Extract the extension from [path] and use that for MIME-type lookup, using
@@ -32,7 +35,7 @@
*/
class MimeTypeResolver {
final Map<String, String> _extensionMap = {};
- final List<_MagicNumber> _magicNumbers = [];
+ final List<MagicNumber> _magicNumbers = [];
final bool _useDefault;
int _magicNumbersMaxLength;
@@ -46,7 +49,7 @@
*/
MimeTypeResolver() :
_useDefault = true,
- _magicNumbersMaxLength = _DEFAULT_MAGIC_NUMBERS_MAX_LENGTH;
+ _magicNumbersMaxLength = defaultMagicNumbersMaxLength;
/**
* Get the maximum number of bytes required to match all magic numbers, when
@@ -71,7 +74,7 @@
result = _matchMagic(headerBytes, _magicNumbers);
if (result != null) return result;
if (_useDefault) {
- result = _matchMagic(headerBytes, _DEFAULT_MAGIC_NUMBERS);
+ result = _matchMagic(headerBytes, DEFAULT_MAGIC_NUMBERS);
if (result != null) return result;
}
}
@@ -79,7 +82,7 @@
result = _extensionMap[ext];
if (result != null) return result;
if (_useDefault) {
- result = _DEFAULT_EXTENSION_MAP[ext];
+ result = DEFAULT_EXTENSION_MAP[ext];
if (result != null) return result;
}
return null;
@@ -106,11 +109,11 @@
if (bytes.length > _magicNumbersMaxLength) {
_magicNumbersMaxLength = bytes.length;
}
- _magicNumbers.add(new _MagicNumber(mimeType, bytes, mask: mask));
+ _magicNumbers.add(new MagicNumber(mimeType, bytes, mask: mask));
}
static String _matchMagic(List<int> headerBytes,
- List<_MagicNumber> magicNumbers) {
+ List<MagicNumber> magicNumbers) {
for (var mn in magicNumbers) {
if (mn.matches(headerBytes)) return mn.mimeType;
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 0ce9b2a..b44361b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,9 +1,9 @@
name: mime
-version: 0.9.0
+version: 0.9.0+1
author: Dart Team <misc@dartlang.org>
description: Helper-package for working with MIME.
homepage: http://www.dartlang.org
-dev_dependencies:
- unittest: ">=0.9.0 <0.10.0"
environment:
- sdk: ">=0.8.10+6 <2.0.0"
+ sdk: '>=1.0.0 <2.0.0'
+dev_dependencies:
+ unittest: '>=0.9.0 <0.11.0'
diff --git a/test/mime_multipart_transformer_test.dart b/test/mime_multipart_transformer_test.dart
index 7d7baca..7bc2d7d 100644
--- a/test/mime_multipart_transformer_test.dart
+++ b/test/mime_multipart_transformer_test.dart
@@ -2,12 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import "package:unittest/unittest.dart";
-import "package:mime/mime.dart";
import 'dart:async';
import 'dart:math';
-void testParse(String message,
+import "package:unittest/unittest.dart";
+import "package:mime/mime.dart";
+
+void _testParse(String message,
String boundary,
[List<Map> expectedHeaders,
List expectedParts,
@@ -67,20 +68,9 @@
});
}
-void testParseValid() {
- String message;
- Map headers;
- Map headers1;
- Map headers2;
- Map headers3;
- Map headers4;
- String body1;
- String body2;
- String body3;
- String body4;
-
+void _testParseValid() {
// Sample from Wikipedia.
- message = """
+ var message = """
This is a message with multiple parts in MIME format.\r
--frontier\r
Content-Type: text/plain\r
@@ -93,14 +83,14 @@
PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg
Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg=\r
--frontier--\r\n""";
- headers1 = <String, String>{"content-type": "text/plain"};
- headers2 = <String, String>{"content-type": "application/octet-stream",
+ var headers1 = <String, String>{"content-type": "text/plain"};
+ var headers2 = <String, String>{"content-type": "application/octet-stream",
"content-transfer-encoding": "base64"};
- body1 = "This is the body of the message.";
- body2 = """
+ var body1 = "This is the body of the message.";
+ var body2 = """
PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg
Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg=""";
- testParse(message, "frontier", [headers1, headers2], [body1, body2]);
+ _testParse(message, "frontier", [headers1, headers2], [body1, body2]);
// Sample from HTML 4.01 Specification.
message = """
@@ -122,7 +112,7 @@
};
body1 = "Larry";
body2 = "... contents of file1.txt ...";
- testParse(message, "AaB03x", [headers1, headers2], [body1, body2]);
+ _testParse(message, "AaB03x", [headers1, headers2], [body1, body2]);
// Longer form from submitting the following from Chrome.
//
@@ -164,15 +154,15 @@
"content-disposition": "form-data; name=\"text_input\""};
headers2 = <String, String>{
"content-disposition": "form-data; name=\"password_input\""};
- headers3 = <String, String>{
+ var headers3 = <String, String>{
"content-disposition": "form-data; name=\"checkbox_input\""};
- headers4 = <String, String>{
+ var headers4 = <String, String>{
"content-disposition": "form-data; name=\"radio_input\""};
body1 = "text";
body2 = "password";
- body3 = "on";
- body4 = "on";
- testParse(message,
+ var body3 = "on";
+ var body4 = "on";
+ _testParse(message,
"----WebKitFormBoundaryQ3cgYAmGRF8yOeYB",
[headers1, headers2, headers3, headers4],
[body1, body2, body3, body4]);
@@ -196,7 +186,7 @@
\r
on\r
-----------------------------52284550912143824192005403738--\r\n""";
- testParse(message,
+ _testParse(message,
"---------------------------52284550912143824192005403738",
[headers1, headers2, headers3, headers4],
[body1, body2, body3, body4]);
@@ -220,7 +210,7 @@
\r
on\r
-----------------------------7dc8f38c60326--\r\n""";
- testParse(message,
+ _testParse(message,
"---------------------------7dc8f38c60326",
[headers1, headers2, headers3, headers4],
[body1, body2, body3, body4]);
@@ -261,7 +251,7 @@
--\r\r\r
-\r\r
--boundary--\r\n""";
- headers = <String, String>{"content-type": "text/plain"};
+ var headers = <String, String>{"content-type": "text/plain"};
body1 = """
-\r
--\r
@@ -282,7 +272,7 @@
--b\r\r\r\r
--\r\r\r
-\r""";
- testParse(message, "boundary", [headers, headers], [body1, body2]);
+ _testParse(message, "boundary", [headers, headers], [body1, body2]);
// Without initial CRLF.
message = """
@@ -295,14 +285,12 @@
\r
Body2\r
--xxx--\r\n""";
- testParse(message, "xxx", null, ["\r\nBody 1", "\r\nBody2"]);
+ _testParse(message, "xxx", null, ["\r\nBody 1", "\r\nBody2"]);
}
-void testParseInvalid() {
- String message;
-
+void _testParseInvalid() {
// Missing end boundary.
- message = """
+ var message = """
\r
--xxx\r
\r
@@ -313,10 +301,10 @@
\r
Body2\r
--xxx\r\n""";
- testParse(message, "xxx", null, [null, null], true);
+ _testParse(message, "xxx", null, [null, null], true);
}
void main() {
- testParseValid();
- testParseInvalid();
+ _testParseValid();
+ _testParseInvalid();
}
diff --git a/test/mime_type_test.dart b/test/mime_type_test.dart
index 36c728d..23cc10e 100644
--- a/test/mime_type_test.dart
+++ b/test/mime_type_test.dart
@@ -2,10 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import "package:unittest/unittest.dart";
-import 'package:mime/mime.dart';
+import 'dart:math' as math;
-void expectMimeType(String path,
+import 'package:unittest/unittest.dart';
+import 'package:mime/mime.dart';
+import 'package:mime/src/magic_number.dart';
+
+void _expectMimeType(String path,
String expectedMimeType,
{List<int> headerBytes,
MimeTypeResolver resolver}) {
@@ -16,51 +19,49 @@
mimeType = resolver.lookup(path, headerBytes: headerBytes);
}
- if (mimeType != expectedMimeType) {
- throw "Expect '$expectedMimeType' but got '$mimeType'";
- }
+ expect(mimeType, expectedMimeType);
}
void main() {
group('global-lookup', () {
test('by-path', () {
- expectMimeType('file.dart', 'application/dart');
+ _expectMimeType('file.dart', 'application/dart');
// Test mixed-case
- expectMimeType('file.DaRT', 'application/dart');
- expectMimeType('file.html', 'text/html');
- expectMimeType('file.xhtml', 'application/xhtml+xml');
- expectMimeType('file.jpeg', 'image/jpeg');
- expectMimeType('file.jpg', 'image/jpeg');
- expectMimeType('file.png', 'image/png');
- expectMimeType('file.gif', 'image/gif');
- expectMimeType('file.cc', 'text/x-c');
- expectMimeType('file.c', 'text/x-c');
- expectMimeType('file.css', 'text/css');
- expectMimeType('file.js', 'application/javascript');
- expectMimeType('file.ps', 'application/postscript');
- expectMimeType('file.pdf', 'application/pdf');
- expectMimeType('file.tiff', 'image/tiff');
- expectMimeType('file.tif', 'image/tiff');
+ _expectMimeType('file.DaRT', 'application/dart');
+ _expectMimeType('file.html', 'text/html');
+ _expectMimeType('file.xhtml', 'application/xhtml+xml');
+ _expectMimeType('file.jpeg', 'image/jpeg');
+ _expectMimeType('file.jpg', 'image/jpeg');
+ _expectMimeType('file.png', 'image/png');
+ _expectMimeType('file.gif', 'image/gif');
+ _expectMimeType('file.cc', 'text/x-c');
+ _expectMimeType('file.c', 'text/x-c');
+ _expectMimeType('file.css', 'text/css');
+ _expectMimeType('file.js', 'application/javascript');
+ _expectMimeType('file.ps', 'application/postscript');
+ _expectMimeType('file.pdf', 'application/pdf');
+ _expectMimeType('file.tiff', 'image/tiff');
+ _expectMimeType('file.tif', 'image/tiff');
});
test('unknown-mime-type', () {
- expectMimeType('file.unsupported-extension', null);
+ _expectMimeType('file.unsupported-extension', null);
});
test('by-header-bytes', () {
- expectMimeType('file.jpg',
+ _expectMimeType('file.jpg',
'image/png',
headerBytes: [0x89, 0x50, 0x4E, 0x47,
0x0D, 0x0A, 0x1A, 0x0A]);
- expectMimeType('file.jpg',
+ _expectMimeType('file.jpg',
'image/gif',
headerBytes: [0x47, 0x49, 0x46, 0x38, 0x39,
0x61, 0x0D, 0x0A, 0x1A, 0x0A]);
- expectMimeType('file.gif',
+ _expectMimeType('file.gif',
'image/jpeg',
headerBytes: [0xFF, 0xD8, 0x46, 0x38, 0x39,
0x61, 0x0D, 0x0A, 0x1A, 0x0A]);
- expectMimeType('file.mp4',
+ _expectMimeType('file.mp4',
'video/mp4',
headerBytes: [0x00, 0x00, 0x00, 0x04, 0x66, 0x74,
0x79, 0x70, 0x33, 0x67, 0x70, 0x35]);
@@ -71,13 +72,13 @@
test('override-extension', () {
var resolver = new MimeTypeResolver();
resolver.addExtension('jpg', 'my-mime-type');
- expectMimeType('file.jpg', 'my-mime-type', resolver: resolver);
+ _expectMimeType('file.jpg', 'my-mime-type', resolver: resolver);
});
test('fallthrough-extension', () {
var resolver = new MimeTypeResolver();
resolver.addExtension('jpg2', 'my-mime-type');
- expectMimeType('file.jpg', 'image/jpeg', resolver: resolver);
+ _expectMimeType('file.jpg', 'image/jpeg', resolver: resolver);
});
test('with-mask', () {
@@ -85,19 +86,26 @@
resolver.addMagicNumber([0x01, 0x02, 0x03],
'my-mime-type',
mask: [0x01, 0xFF, 0xFE]);
- expectMimeType('file',
+ _expectMimeType('file',
'my-mime-type',
headerBytes: [0x01, 0x02, 0x03],
resolver: resolver);
- expectMimeType('file',
+ _expectMimeType('file',
null,
headerBytes: [0x01, 0x03, 0x03],
resolver: resolver);
- expectMimeType('file',
+ _expectMimeType('file',
'my-mime-type',
headerBytes: [0xFF, 0x02, 0x02],
resolver: resolver);
});
});
-}
+ test('default magic number', () {
+ var actualMaxBytes = DEFAULT_MAGIC_NUMBERS.fold(0, (previous, magic) {
+ return math.max(previous, magic.numbers.length);
+ });
+
+ expect(defaultMagicNumbersMaxLength, actualMaxBytes);
+ });
+}