Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
68fb3e48
Commit
68fb3e48
authored
Mar 08, 2017
by
Ian Hickson
Committed by
GitHub
Mar 08, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Farewell, local fork of the http package. (#8642)
parent
90774c18
Changes
28
Hide whitespace changes
Inline
Side-by-side
Showing
28 changed files
with
48 additions
and
1787 deletions
+48
-1787
stock_data.dart
examples/stocks/lib/stock_data.dart
+10
-6
pubspec.yaml
examples/stocks/pubspec.yaml
+1
-0
http.dart
packages/flutter/lib/http.dart
+0
-20
services.dart
packages/flutter/lib/services.dart
+3
-2
.dartignore
packages/flutter/lib/src/http/.dartignore
+0
-0
README.md
packages/flutter/lib/src/http/README.md
+0
-7
base_client.dart
packages/flutter/lib/src/http/base_client.dart
+0
-199
base_request.dart
packages/flutter/lib/src/http/base_request.dart
+0
-141
base_response.dart
packages/flutter/lib/src/http/base_response.dart
+0
-53
byte_stream.dart
packages/flutter/lib/src/http/byte_stream.dart
+0
-36
client.dart
packages/flutter/lib/src/http/client.dart
+0
-148
exception.dart
packages/flutter/lib/src/http/exception.dart
+0
-16
http.dart
packages/flutter/lib/src/http/http.dart
+0
-171
io.dart
packages/flutter/lib/src/http/io.dart
+0
-26
io_client.dart
packages/flutter/lib/src/http/io_client.dart
+0
-90
mock_client.dart
packages/flutter/lib/src/http/mock_client.dart
+0
-88
multipart_file.dart
packages/flutter/lib/src/http/multipart_file.dart
+0
-111
multipart_request.dart
packages/flutter/lib/src/http/multipart_request.dart
+0
-177
request.dart
packages/flutter/lib/src/http/request.dart
+0
-164
response.dart
packages/flutter/lib/src/http/response.dart
+0
-95
streamed_request.dart
packages/flutter/lib/src/http/streamed_request.dart
+0
-42
streamed_response.dart
packages/flutter/lib/src/http/streamed_response.dart
+0
-39
utils.dart
packages/flutter/lib/src/http/utils.dart
+0
-143
asset_bundle.dart
packages/flutter/lib/src/services/asset_bundle.dart
+8
-4
http_client.dart
packages/flutter/lib/src/services/http_client.dart
+16
-0
image_provider.dart
packages/flutter/lib/src/services/image_provider.dart
+5
-2
pubspec.yaml
packages/flutter/pubspec.yaml
+1
-5
binding.dart
packages/flutter_test/lib/src/binding.dart
+4
-2
No files found.
examples/stocks/lib/stock_data.dart
View file @
68fb3e48
...
@@ -10,7 +10,8 @@
...
@@ -10,7 +10,8 @@
import
'dart:convert'
;
import
'dart:convert'
;
import
'dart:math'
as
math
;
import
'dart:math'
as
math
;
import
'package:flutter/http.dart'
as
http
;
import
'package:flutter/services.dart'
;
import
'package:http/http.dart'
as
http
;
final
math
.
Random
_rng
=
new
math
.
Random
();
final
math
.
Random
_rng
=
new
math
.
Random
();
...
@@ -60,19 +61,22 @@ String _urlToFetch(int chunk) {
...
@@ -60,19 +61,22 @@ String _urlToFetch(int chunk) {
}
}
class
StockDataFetcher
{
class
StockDataFetcher
{
int
_nextChunk
=
0
;
StockDataFetcher
(
this
.
callback
)
{
_httpClient
=
createHttpClient
();
_fetchNextChunk
();
}
final
StockDataCallback
callback
;
final
StockDataCallback
callback
;
http
.
Client
_httpClient
;
static
bool
actuallyFetchData
=
true
;
static
bool
actuallyFetchData
=
true
;
StockDataFetcher
(
this
.
callback
)
{
int
_nextChunk
=
0
;
_fetchNextChunk
();
}
void
_fetchNextChunk
()
{
void
_fetchNextChunk
()
{
if
(!
actuallyFetchData
)
if
(!
actuallyFetchData
)
return
;
return
;
http
.
get
(
_urlToFetch
(
_nextChunk
++)).
then
<
Null
>((
http
.
Response
response
)
{
_httpClient
.
get
(
_urlToFetch
(
_nextChunk
++)).
then
<
Null
>((
http
.
Response
response
)
{
final
String
json
=
response
.
body
;
final
String
json
=
response
.
body
;
if
(
json
==
null
)
{
if
(
json
==
null
)
{
print
(
"Failed to load stock data chunk
${_nextChunk - 1}
"
);
print
(
"Failed to load stock data chunk
${_nextChunk - 1}
"
);
...
...
examples/stocks/pubspec.yaml
View file @
68fb3e48
...
@@ -3,6 +3,7 @@ dependencies:
...
@@ -3,6 +3,7 @@ dependencies:
flutter
:
flutter
:
sdk
:
flutter
sdk
:
flutter
intl
:
'
>=0.14.0
<0.15.0'
intl
:
'
>=0.14.0
<0.15.0'
http
:
'
>=0.11.3+11'
dev_dependencies
:
dev_dependencies
:
flutter_test
:
flutter_test
:
...
...
packages/flutter/lib/http.dart
deleted
100644 → 0
View file @
90774c18
// Copyright 2015 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.
/// A [Future]-based library for making HTTP requests.
///
/// To use, import `package:flutter/http.dart`.
///
/// This library is based on Dart's `http` package, but differs in that it does
/// not have a dependency on mirrors.
///
// TODO(chinmaygarde): The contents of `lib/src/http` will become redundant
// once https://github.com/dart-lang/http/issues/1 is fixed (removes the use
// of mirrors). Once that issue is addressed, we should get rid this directory
// and use `dart-lang/http` directly.
library
http
;
export
'src/http/http.dart'
;
export
'src/http/mock_client.dart'
;
export
'src/http/response.dart'
;
packages/flutter/lib/services.dart
View file @
68fb3e48
...
@@ -13,14 +13,15 @@ library services;
...
@@ -13,14 +13,15 @@ library services;
export
'src/services/asset_bundle.dart'
;
export
'src/services/asset_bundle.dart'
;
export
'src/services/binding.dart'
;
export
'src/services/binding.dart'
;
export
'src/services/clipboard.dart'
;
export
'src/services/clipboard.dart'
;
export
'src/services/message_codec.dart'
;
export
'src/services/message_codecs.dart'
;
export
'src/services/haptic_feedback.dart'
;
export
'src/services/haptic_feedback.dart'
;
export
'src/services/http_client.dart'
;
export
'src/services/image_cache.dart'
;
export
'src/services/image_cache.dart'
;
export
'src/services/image_decoder.dart'
;
export
'src/services/image_decoder.dart'
;
export
'src/services/image_provider.dart'
;
export
'src/services/image_provider.dart'
;
export
'src/services/image_resolution.dart'
;
export
'src/services/image_resolution.dart'
;
export
'src/services/image_stream.dart'
;
export
'src/services/image_stream.dart'
;
export
'src/services/message_codec.dart'
;
export
'src/services/message_codecs.dart'
;
export
'src/services/path_provider.dart'
;
export
'src/services/path_provider.dart'
;
export
'src/services/platform_channel.dart'
;
export
'src/services/platform_channel.dart'
;
export
'src/services/platform_messages.dart'
;
export
'src/services/platform_messages.dart'
;
...
...
packages/flutter/lib/src/http/.dartignore
deleted
100644 → 0
View file @
90774c18
packages/flutter/lib/src/http/README.md
deleted
100644 → 0
View file @
90774c18
`dart-lang/http` without Mirrors
================================
The contents of this will become redundant once
https://github.com/dart-lang/http/issues/1 is fixed (removes the use
of mirrors). Once that issue is addressed, we should get rid this directory
and use
`dart-lang/http`
directly.
packages/flutter/lib/src/http/base_client.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// 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
'dart:async'
;
import
'dart:convert'
;
import
'dart:typed_data'
;
import
'package:collection/collection.dart'
;
import
'base_request.dart'
;
import
'client.dart'
;
import
'exception.dart'
;
import
'request.dart'
;
import
'response.dart'
;
import
'streamed_response.dart'
;
/// The abstract base class for an HTTP client. This is a mixin-style class;
/// subclasses only need to implement [send] and maybe [close], and then they
/// get various convenience methods for free.
abstract
class
BaseClient
implements
Client
{
/// Sends an HTTP HEAD request with the given headers to the given URL, which
/// can be a [Uri] or a [String].
///
/// For more fine-grained control over the request, use [send] instead.
@override
Future
<
Response
>
head
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
})
=>
_sendUnstreamed
(
"HEAD"
,
url
,
headers
);
/// Sends an HTTP GET request with the given headers to the given URL, which
/// can be a [Uri] or a [String].
///
/// For more fine-grained control over the request, use [send] instead.
@override
Future
<
Response
>
get
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
})
=>
_sendUnstreamed
(
"GET"
,
url
,
headers
);
/// Sends an HTTP POST request with the given headers and body to the given
/// URL, which can be a [Uri] or a [String].
///
/// [body] sets the body of the request. It can be a [String], a [List<int>]
/// or a [Map<String, String>]. If it's a String, it's encoded using
/// [encoding] and used as the body of the request. The content-type of the
/// request will default to "text/plain".
///
/// If [body] is a List, it's used as a list of bytes for the body of the
/// request.
///
/// If [body] is a Map, it's encoded as form fields using [encoding]. The
/// content-type of the request will be set to
/// `"application/x-www-form-urlencoded"`; this cannot be overridden.
///
/// [encoding] defaults to UTF-8.
///
/// For more fine-grained control over the request, use [send] instead.
@override
Future
<
Response
>
post
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
,
dynamic
body
,
Encoding
encoding
})
=>
_sendUnstreamed
(
"POST"
,
url
,
headers
,
body
,
encoding
);
/// Sends an HTTP PUT request with the given headers and body to the given
/// URL, which can be a [Uri] or a [String].
///
/// [body] sets the body of the request. It can be a [String], a [List<int>]
/// or a [Map<String, String>]. If it's a String, it's encoded using
/// [encoding] and used as the body of the request. The content-type of the
/// request will default to "text/plain".
///
/// If [body] is a List, it's used as a list of bytes for the body of the
/// request.
///
/// If [body] is a Map, it's encoded as form fields using [encoding]. The
/// content-type of the request will be set to
/// `"application/x-www-form-urlencoded"`; this cannot be overridden.
///
/// [encoding] defaults to UTF-8.
///
/// For more fine-grained control over the request, use [send] instead.
@override
Future
<
Response
>
put
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
,
dynamic
body
,
Encoding
encoding
})
=>
_sendUnstreamed
(
"PUT"
,
url
,
headers
,
body
,
encoding
);
/// Sends an HTTP PATCH request with the given headers and body to the given
/// URL, which can be a [Uri] or a [String].
///
/// [body] sets the body of the request. It can be a [String], a [List<int>]
/// or a [Map<String, String>]. If it's a String, it's encoded using
/// [encoding] and used as the body of the request. The content-type of the
/// request will default to "text/plain".
///
/// If [body] is a List, it's used as a list of bytes for the body of the
/// request.
///
/// If [body] is a Map, it's encoded as form fields using [encoding]. The
/// content-type of the request will be set to
/// `"application/x-www-form-urlencoded"`; this cannot be overridden.
///
/// [encoding] defaults to UTF-8.
///
/// For more fine-grained control over the request, use [send] instead.
@override
Future
<
Response
>
patch
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
,
dynamic
body
,
Encoding
encoding
})
=>
_sendUnstreamed
(
"PATCH"
,
url
,
headers
,
body
,
encoding
);
/// Sends an HTTP DELETE request with the given headers to the given URL,
/// which can be a [Uri] or a [String].
///
/// For more fine-grained control over the request, use [send] instead.
@override
Future
<
Response
>
delete
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
})
=>
_sendUnstreamed
(
"DELETE"
,
url
,
headers
);
/// Sends an HTTP GET request with the given headers to the given URL, which
/// can be a [Uri] or a [String], and returns a Future that completes to the
/// body of the response as a String.
///
/// The Future will emit a [ClientException] if the response doesn't have a
/// success status code.
///
/// For more fine-grained control over the request and response, use [send] or
/// [get] instead.
@override
Future
<
String
>
read
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
})
{
return
get
(
url
,
headers:
headers
).
then
((
Response
response
)
{
_checkResponseSuccess
(
url
,
response
);
return
response
.
body
;
});
}
/// Sends an HTTP GET request with the given headers to the given URL, which
/// can be a [Uri] or a [String], and returns a Future that completes to the
/// body of the response as a list of bytes.
///
/// The Future will emit an [ClientException] if the response doesn't have a
/// success status code.
///
/// For more fine-grained control over the request and response, use [send] or
/// [get] instead.
@override
Future
<
Uint8List
>
readBytes
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
})
{
return
get
(
url
,
headers:
headers
).
then
((
Response
response
)
{
_checkResponseSuccess
(
url
,
response
);
return
response
.
bodyBytes
;
});
}
/// Sends an HTTP request and asynchronously returns the response.
///
/// Implementers should call [BaseRequest.finalize] to get the body of the
/// request as a [ByteStream]. They shouldn't make any assumptions about the
/// state of the stream; it could have data written to it asynchronously at a
/// later point, or it could already be closed when it's returned. Any
/// internal HTTP errors should be wrapped as [ClientException]s.
@override
Future
<
StreamedResponse
>
send
(
BaseRequest
request
);
/// Sends a non-streaming [Request] and returns a non-streaming [Response].
Future
<
Response
>
_sendUnstreamed
(
String
method
,
dynamic
url
,
Map
<
String
,
String
>
headers
,
[
dynamic
body
,
Encoding
encoding
])
async
{
if
(
url
is
String
)
url
=
Uri
.
parse
(
url
);
Request
request
=
new
Request
(
method
,
url
);
if
(
headers
!=
null
)
request
.
headers
.
addAll
(
headers
);
if
(
encoding
!=
null
)
request
.
encoding
=
encoding
;
if
(
body
!=
null
)
{
if
(
body
is
String
)
{
request
.
body
=
body
;
}
else
if
(
body
is
List
)
{
request
.
bodyBytes
=
DelegatingList
.
typed
(
body
);
}
else
if
(
body
is
Map
)
{
request
.
bodyFields
=
DelegatingMap
.
typed
(
body
);
}
else
{
throw
new
ArgumentError
(
'Invalid request body "
$body
".'
);
}
}
return
Response
.
fromStream
(
await
send
(
request
));
}
/// Throws an error if [response] is not successful.
void
_checkResponseSuccess
(
dynamic
url
,
Response
response
)
{
if
(
response
.
statusCode
<
400
)
return
;
String
message
=
"Request to
$url
failed with status
${response.statusCode}
"
;
if
(
response
.
reasonPhrase
!=
null
)
{
message
=
"
$message
:
${response.reasonPhrase}
"
;
}
if
(
url
is
String
)
url
=
Uri
.
parse
(
url
);
throw
new
ClientException
(
"
$message
."
,
url
);
}
/// Closes the client and cleans up any resources associated with it. It's
/// important to close each client when it's done being used; failing to do so
/// can cause the Dart process to hang.
@override
void
close
()
{}
}
packages/flutter/lib/src/http/base_request.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// 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
'dart:async'
;
import
'dart:collection'
;
import
'byte_stream.dart'
;
import
'client.dart'
;
import
'streamed_response.dart'
;
import
'utils.dart'
;
/// The base class for HTTP requests.
///
/// Subclasses of [BaseRequest] can be constructed manually and passed to
/// [BaseClient.send], which allows the user to provide fine-grained control
/// over the request properties. However, usually it's easier to use convenience
/// methods like [get] or [BaseClient.get].
abstract
class
BaseRequest
{
/// The HTTP method of the request. Most commonly "GET" or "POST", less
/// commonly "HEAD", "PUT", or "DELETE". Non-standard method names are also
/// supported.
final
String
method
;
/// The URL to which the request will be sent.
final
Uri
url
;
/// Creates a new HTTP request.
BaseRequest
(
this
.
method
,
this
.
url
)
:
headers
=
new
LinkedHashMap
<
String
,
String
>(
equals:
(
String
key1
,
String
key2
)
=>
key1
.
toLowerCase
()
==
key2
.
toLowerCase
(),
hashCode:
(
String
key
)
=>
key
.
toLowerCase
().
hashCode
);
/// The size of the request body, in bytes.
///
/// This defaults to `null`, which indicates that the size of the request is
/// not known in advance.
int
get
contentLength
=>
_contentLength
;
int
_contentLength
;
set
contentLength
(
int
value
)
{
if
(
value
!=
null
&&
value
<
0
)
{
throw
new
ArgumentError
(
"Invalid content length
$value
."
);
}
_checkFinalized
();
_contentLength
=
value
;
}
/// Whether a persistent connection should be maintained with the server.
/// Defaults to true.
bool
get
persistentConnection
=>
_persistentConnection
;
bool
_persistentConnection
=
true
;
set
persistentConnection
(
bool
value
)
{
_checkFinalized
();
_persistentConnection
=
value
;
}
/// Whether the client should follow redirects while resolving this request.
/// Defaults to true.
bool
get
followRedirects
=>
_followRedirects
;
bool
_followRedirects
=
true
;
set
followRedirects
(
bool
value
)
{
_checkFinalized
();
_followRedirects
=
value
;
}
/// The maximum number of redirects to follow when [followRedirects] is true.
/// If this number is exceeded the [BaseResponse] future will signal a
/// [RedirectException]. Defaults to 5.
int
get
maxRedirects
=>
_maxRedirects
;
int
_maxRedirects
=
5
;
set
maxRedirects
(
int
value
)
{
_checkFinalized
();
_maxRedirects
=
value
;
}
// TODO(nweiz): automatically parse cookies from headers
// TODO(nweiz): make this a HttpHeaders object
/// The headers for this request.
final
Map
<
String
,
String
>
headers
;
/// Whether the request has been finalized.
bool
get
finalized
=>
_finalized
;
bool
_finalized
=
false
;
/// Finalizes the HTTP request in preparation for it being sent. This freezes
/// all mutable fields and returns a single-subscription [ByteStream] that
/// emits the body of the request.
///
/// The base implementation of this returns null rather than a [ByteStream];
/// subclasses are responsible for creating the return value, which should be
/// single-subscription to ensure that no data is dropped. They should also
/// freeze any additional mutable fields they add that don't make sense to
/// change after the request headers are sent.
ByteStream
finalize
()
{
// TODO(nweiz): freeze headers
if
(
finalized
)
throw
new
StateError
(
"Can't finalize a finalized Request."
);
_finalized
=
true
;
return
null
;
}
/// Sends this request.
///
/// This automatically initializes a new [Client] and closes that client once
/// the request is complete. If you're planning on making multiple requests to
/// the same server, you should use a single [Client] for all of those
/// requests.
Future
<
StreamedResponse
>
send
()
async
{
Client
client
=
new
Client
();
try
{
StreamedResponse
response
=
await
client
.
send
(
this
);
Stream
<
dynamic
>
stream
=
onDone
(
response
.
stream
,
client
.
close
);
return
new
StreamedResponse
(
new
ByteStream
(
stream
),
response
.
statusCode
,
contentLength:
response
.
contentLength
,
request:
response
.
request
,
headers:
response
.
headers
,
isRedirect:
response
.
isRedirect
,
persistentConnection:
response
.
persistentConnection
,
reasonPhrase:
response
.
reasonPhrase
);
}
catch
(
ex
)
{
client
.
close
();
rethrow
;
}
}
// Throws an error if this request has been finalized.
void
_checkFinalized
()
{
if
(!
finalized
)
return
;
throw
new
StateError
(
"Can't modify a finalized Request."
);
}
@override
String
toString
()
=>
"
$method
$url
"
;
}
packages/flutter/lib/src/http/base_response.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// 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
'base_request.dart'
;
/// The base class for HTTP responses.
///
/// Subclasses of [BaseResponse] are usually not constructed manually; instead,
/// they're returned by [BaseClient.send] or other HTTP client methods.
abstract
class
BaseResponse
{
/// The (frozen) request that triggered this response.
final
BaseRequest
request
;
/// The status code of the response.
final
int
statusCode
;
/// The reason phrase associated with the status code.
final
String
reasonPhrase
;
/// The size of the response body, in bytes.
///
/// If the size of the request is not known in advance, this is `null`.
final
int
contentLength
;
// TODO(nweiz): automatically parse cookies from headers
// TODO(nweiz): make this a HttpHeaders object.
/// The headers for this response.
final
Map
<
String
,
String
>
headers
;
/// Whether this response is a redirect.
final
bool
isRedirect
;
/// Whether the server requested that a persistent connection be maintained.
final
bool
persistentConnection
;
/// Creates a new HTTP response.
BaseResponse
(
this
.
statusCode
,
{
this
.
contentLength
,
this
.
request
,
this
.
headers
:
const
<
String
,
String
>{},
this
.
isRedirect
:
false
,
this
.
persistentConnection
:
true
,
this
.
reasonPhrase
})
{
if
(
statusCode
<
100
)
{
throw
new
ArgumentError
(
"Invalid status code
$statusCode
."
);
}
else
if
(
contentLength
!=
null
&&
contentLength
<
0
)
{
throw
new
ArgumentError
(
"Invalid content length
$contentLength
."
);
}
}
}
packages/flutter/lib/src/http/byte_stream.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// 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
'dart:async'
;
import
'dart:convert'
;
import
'dart:typed_data'
;
/// A stream of chunks of bytes representing a single piece of data.
class
ByteStream
extends
StreamView
<
List
<
int
>>
{
ByteStream
(
Stream
<
List
<
int
>>
stream
)
:
super
(
stream
);
/// Returns a single-subscription byte stream that will emit the given bytes
/// in a single chunk.
factory
ByteStream
.
fromBytes
(
List
<
int
>
bytes
)
=>
new
ByteStream
(
new
Stream
<
dynamic
>.
fromIterable
(<
List
<
int
>>[
bytes
]));
/// Collects the data of this stream in a [Uint8List].
Future
<
Uint8List
>
toBytes
()
{
Completer
<
Uint8List
>
completer
=
new
Completer
<
Uint8List
>();
dynamic
sink
=
new
ByteConversionSink
.
withCallback
((
dynamic
bytes
)
=>
completer
.
complete
(
new
Uint8List
.
fromList
(
bytes
)));
listen
(
sink
.
add
,
onError:
completer
.
completeError
,
onDone:
sink
.
close
,
cancelOnError:
true
);
return
completer
.
future
;
}
/// Collect the data of this stream in a [String], decoded according to
/// [encoding], which defaults to `UTF8`.
Future
<
String
>
bytesToString
([
Encoding
encoding
=
UTF8
])
=>
encoding
.
decodeStream
(
this
);
Stream
<
String
>
toStringStream
([
Encoding
encoding
=
UTF8
])
=>
encoding
.
decoder
.
bind
(
this
);
}
packages/flutter/lib/src/http/client.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// 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
'dart:async'
;
import
'dart:convert'
;
import
'dart:typed_data'
;
import
'base_client.dart'
;
import
'base_request.dart'
;
import
'io_client.dart'
;
import
'response.dart'
;
import
'streamed_response.dart'
;
typedef
Client
ClientOverride
(
);
/// The interface for HTTP clients that take care of maintaining persistent
/// connections across multiple requests to the same server. If you only need to
/// send a single request, it's usually easier to use [head], [get], [post],
/// [put], [patch], or [delete] instead.
///
/// When creating an HTTP client class with additional functionality, you must
/// extend [BaseClient] rather than [Client]. In most cases, you can wrap
/// another instance of [Client] and add functionality on top of that. This
/// allows all classes implementing [Client] to be mutually composable.
abstract
class
Client
{
/// Creates a new client.
///
/// Currently this will create an [IOClient] if `dart:io` is available and
/// throw an [UnsupportedError] otherwise. In the future, it will create a
/// [BrowserClient] if `dart:html` is available.
factory
Client
()
{
return
clientOverride
==
null
?
new
IOClient
()
:
clientOverride
();
}
static
ClientOverride
clientOverride
;
/// Sends an HTTP HEAD request with the given headers to the given URL, which
/// can be a [Uri] or a [String].
///
/// For more fine-grained control over the request, use [send] instead.
Future
<
Response
>
head
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
});
/// Sends an HTTP GET request with the given headers to the given URL, which
/// can be a [Uri] or a [String].
///
/// For more fine-grained control over the request, use [send] instead.
Future
<
Response
>
get
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
});
/// Sends an HTTP POST request with the given headers and body to the given
/// URL, which can be a [Uri] or a [String].
///
/// [body] sets the body of the request. It can be a [String], a [List<int>]
/// or a [Map<String, String>]. If it's a String, it's encoded using
/// [encoding] and used as the body of the request. The content-type of the
/// request will default to "text/plain".
///
/// If [body] is a List, it's used as a list of bytes for the body of the
/// request.
///
/// If [body] is a Map, it's encoded as form fields using [encoding]. The
/// content-type of the request will be set to
/// `"application/x-www-form-urlencoded"`; this cannot be overridden.
///
/// [encoding] defaults to [UTF8].
///
/// For more fine-grained control over the request, use [send] instead.
Future
<
Response
>
post
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
,
dynamic
body
,
Encoding
encoding
});
/// Sends an HTTP PUT request with the given headers and body to the given
/// URL, which can be a [Uri] or a [String].
///
/// [body] sets the body of the request. It can be a [String], a [List<int>]
/// or a [Map<String, String>]. If it's a String, it's encoded using
/// [encoding] and used as the body of the request. The content-type of the
/// request will default to "text/plain".
///
/// If [body] is a List, it's used as a list of bytes for the body of the
/// request.
///
/// If [body] is a Map, it's encoded as form fields using [encoding]. The
/// content-type of the request will be set to
/// `"application/x-www-form-urlencoded"`; this cannot be overridden.
///
/// [encoding] defaults to [UTF8].
///
/// For more fine-grained control over the request, use [send] instead.
Future
<
Response
>
put
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
,
dynamic
body
,
Encoding
encoding
});
/// Sends an HTTP PATCH request with the given headers and body to the given
/// URL, which can be a [Uri] or a [String].
///
/// [body] sets the body of the request. It can be a [String], a [List<int>]
/// or a [Map<String, String>]. If it's a String, it's encoded using
/// [encoding] and used as the body of the request. The content-type of the
/// request will default to "text/plain".
///
/// If [body] is a List, it's used as a list of bytes for the body of the
/// request.
///
/// If [body] is a Map, it's encoded as form fields using [encoding]. The
/// content-type of the request will be set to
/// `"application/x-www-form-urlencoded"`; this cannot be overridden.
///
/// [encoding] defaults to [UTF8].
///
/// For more fine-grained control over the request, use [send] instead.
Future
<
Response
>
patch
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
,
dynamic
body
,
Encoding
encoding
});
/// Sends an HTTP DELETE request with the given headers to the given URL,
/// which can be a [Uri] or a [String].
///
/// For more fine-grained control over the request, use [send] instead.
Future
<
Response
>
delete
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
});
/// Sends an HTTP GET request with the given headers to the given URL, which
/// can be a [Uri] or a [String], and returns a Future that completes to the
/// body of the response as a String.
///
/// The Future will emit a [ClientException] if the response doesn't have a
/// success status code.
///
/// For more fine-grained control over the request and response, use [send] or
/// [get] instead.
Future
<
String
>
read
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
});
/// Sends an HTTP GET request with the given headers to the given URL, which
/// can be a [Uri] or a [String], and returns a Future that completes to the
/// body of the response as a list of bytes.
///
/// The Future will emit a [ClientException] if the response doesn't have a
/// success status code.
///
/// For more fine-grained control over the request and response, use [send] or
/// [get] instead.
Future
<
Uint8List
>
readBytes
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
});
/// Sends an HTTP request and asynchronously returns the response.
Future
<
StreamedResponse
>
send
(
BaseRequest
request
);
/// Closes the client and cleans up any resources associated with it. It's
/// important to close each client when it's done being used; failing to do so
/// can cause the Dart process to hang.
void
close
();
}
packages/flutter/lib/src/http/exception.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// 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.
/// An exception caused by an error in a pkg/http client.
class
ClientException
implements
Exception
{
final
String
message
;
/// The URL of the HTTP request or response that failed.
final
Uri
uri
;
ClientException
(
this
.
message
,
[
this
.
uri
]);
@override
String
toString
()
=>
message
;
}
packages/flutter/lib/src/http/http.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// 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.
/// A composable, [Future]-based library for making HTTP requests.
import
'dart:async'
;
import
'dart:convert'
;
import
'dart:typed_data'
;
import
'client.dart'
;
import
'response.dart'
;
export
'base_client.dart'
;
export
'base_request.dart'
;
export
'base_response.dart'
;
export
'byte_stream.dart'
;
export
'client.dart'
;
export
'exception.dart'
;
export
'io_client.dart'
;
export
'multipart_file.dart'
;
export
'multipart_request.dart'
;
export
'request.dart'
;
export
'response.dart'
;
export
'streamed_request.dart'
;
export
'streamed_response.dart'
;
/// Sends an HTTP HEAD request with the given headers to the given URL, which
/// can be a [Uri] or a [String].
///
/// This automatically initializes a new [Client] and closes that client once
/// the request is complete. If you're planning on making multiple requests to
/// the same server, you should use a single [Client] for all of those requests.
///
/// For more fine-grained control over the request, use [Request] instead.
Future
<
Response
>
head
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
})
=>
_withClient
((
Client
client
)
=>
client
.
head
(
url
,
headers:
headers
));
/// Sends an HTTP GET request with the given headers to the given URL, which can
/// be a [Uri] or a [String].
///
/// This automatically initializes a new [Client] and closes that client once
/// the request is complete. If you're planning on making multiple requests to
/// the same server, you should use a single [Client] for all of those requests.
///
/// For more fine-grained control over the request, use [Request] instead.
Future
<
Response
>
get
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
})
=>
_withClient
((
Client
client
)
=>
client
.
get
(
url
,
headers:
headers
));
/// Sends an HTTP POST request with the given headers and body to the given URL,
/// which can be a [Uri] or a [String].
///
/// [body] sets the body of the request. It can be a [String], a [List<int>] or
/// a [Map<String, String>]. If it's a String, it's encoded using [encoding] and
/// used as the body of the request. The content-type of the request will
/// default to "text/plain".
///
/// If [body] is a List, it's used as a list of bytes for the body of the
/// request.
///
/// If [body] is a Map, it's encoded as form fields using [encoding]. The
/// content-type of the request will be set to
/// `"application/x-www-form-urlencoded"`; this cannot be overridden.
///
/// [encoding] defaults to [UTF8].
///
/// For more fine-grained control over the request, use [Request] or
/// [StreamedRequest] instead.
Future
<
Response
>
post
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
,
dynamic
body
,
Encoding
encoding
})
=>
_withClient
((
Client
client
)
=>
client
.
post
(
url
,
headers:
headers
,
body:
body
,
encoding:
encoding
));
/// Sends an HTTP PUT request with the given headers and body to the given URL,
/// which can be a [Uri] or a [String].
///
/// [body] sets the body of the request. It can be a [String], a [List<int>] or
/// a [Map<String, String>]. If it's a String, it's encoded using [encoding] and
/// used as the body of the request. The content-type of the request will
/// default to "text/plain".
///
/// If [body] is a List, it's used as a list of bytes for the body of the
/// request.
///
/// If [body] is a Map, it's encoded as form fields using [encoding]. The
/// content-type of the request will be set to
/// `"application/x-www-form-urlencoded"`; this cannot be overridden.
///
/// [encoding] defaults to [UTF8].
///
/// For more fine-grained control over the request, use [Request] or
/// [StreamedRequest] instead.
Future
<
Response
>
put
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
,
dynamic
body
,
Encoding
encoding
})
=>
_withClient
((
Client
client
)
=>
client
.
put
(
url
,
headers:
headers
,
body:
body
,
encoding:
encoding
));
/// Sends an HTTP PATCH request with the given headers and body to the given
/// URL, which can be a [Uri] or a [String].
///
/// [body] sets the body of the request. It can be a [String], a [List<int>] or
/// a [Map<String, String>]. If it's a String, it's encoded using [encoding] and
/// used as the body of the request. The content-type of the request will
/// default to "text/plain".
///
/// If [body] is a List, it's used as a list of bytes for the body of the
/// request.
///
/// If [body] is a Map, it's encoded as form fields using [encoding]. The
/// content-type of the request will be set to
/// `"application/x-www-form-urlencoded"`; this cannot be overridden.
///
/// [encoding] defaults to [UTF8].
///
/// For more fine-grained control over the request, use [Request] or
/// [StreamedRequest] instead.
Future
<
Response
>
patch
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
,
dynamic
body
,
Encoding
encoding
})
=>
_withClient
((
Client
client
)
=>
client
.
patch
(
url
,
headers:
headers
,
body:
body
,
encoding:
encoding
));
/// Sends an HTTP DELETE request with the given headers to the given URL, which
/// can be a [Uri] or a [String].
///
/// This automatically initializes a new [Client] and closes that client once
/// the request is complete. If you're planning on making multiple requests to
/// the same server, you should use a single [Client] for all of those requests.
///
/// For more fine-grained control over the request, use [Request] instead.
Future
<
Response
>
delete
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
})
=>
_withClient
((
Client
client
)
=>
client
.
delete
(
url
,
headers:
headers
));
/// Sends an HTTP GET request with the given headers to the given URL, which can
/// be a [Uri] or a [String], and returns a Future that completes to the body of
/// the response as a [String].
///
/// The Future will emit a [ClientException] if the response doesn't have a
/// success status code.
///
/// This automatically initializes a new [Client] and closes that client once
/// the request is complete. If you're planning on making multiple requests to
/// the same server, you should use a single [Client] for all of those requests.
///
/// For more fine-grained control over the request and response, use [Request]
/// instead.
Future
<
String
>
read
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
})
=>
_withClient
((
Client
client
)
=>
client
.
read
(
url
,
headers:
headers
));
/// Sends an HTTP GET request with the given headers to the given URL, which can
/// be a [Uri] or a [String], and returns a Future that completes to the body of
/// the response as a list of bytes.
///
/// The Future will emit a [ClientException] if the response doesn't have a
/// success status code.
///
/// This automatically initializes a new [Client] and closes that client once
/// the request is complete. If you're planning on making multiple requests to
/// the same server, you should use a single [Client] for all of those requests.
///
/// For more fine-grained control over the request and response, use [Request]
/// instead.
Future
<
Uint8List
>
readBytes
(
dynamic
url
,
{
Map
<
String
,
String
>
headers
})
=>
_withClient
((
Client
client
)
=>
client
.
readBytes
(
url
,
headers:
headers
));
Future
/*<T>*/
_withClient
/*<T>*/
(
Future
/*<T>*/
fn
(
Client
client
))
async
{
Client
client
=
new
Client
();
try
{
return
await
fn
(
client
);
}
finally
{
client
.
close
();
}
}
packages/flutter/lib/src/http/io.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// 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
'dart:io'
as
io
;
/// Whether `dart:io` is supported on this platform.
bool
get
supported
=>
true
;
/// Asserts that the [name]d `dart:io` feature is supported on this platform.
///
/// If `dart:io` doesn't work on this platform, this throws an
/// [UnsupportedError].
void
assertSupported
(
String
name
)
{}
/// Creates a new `dart:io` HttpClient instance.
io
.
HttpClient
newHttpClient
(
)
=>
new
io
.
HttpClient
();
/// Creates a new `dart:io` File instance with the given [path].
io
.
File
newFile
(
String
path
)
=>
new
io
.
File
(
path
);
/// Returns whether [error] is a `dart:io` HttpException.
bool
isHttpException
(
dynamic
error
)
=>
error
is
io
.
HttpException
;
/// Returns whether [client] is a `dart:io` HttpClient.
bool
isHttpClient
(
dynamic
client
)
=>
client
is
io
.
HttpClient
;
packages/flutter/lib/src/http/io_client.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// 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
'dart:async'
;
import
'package:async/async.dart'
;
import
'base_client.dart'
;
import
'base_request.dart'
;
import
'exception.dart'
;
import
'io.dart'
as
io
;
import
'streamed_response.dart'
;
/// A `dart:io`-based HTTP client.
///
/// This is the default client when running on the command line.
class
IOClient
extends
BaseClient
{
/// The underlying `dart:io` HTTP client.
dynamic
_inner
;
/// Creates a new HTTP client.
///
/// [innerClient] must be a `dart:io` HTTP client. If it's not passed, a
/// default one will be instantiated.
IOClient
([
dynamic
innerClient
])
{
io
.
assertSupported
(
"IOClient"
);
if
(
innerClient
!=
null
)
{
// TODO(nweiz): remove this assert when we can type [innerClient]
// properly.
assert
(
io
.
isHttpClient
(
innerClient
));
_inner
=
innerClient
;
}
else
{
_inner
=
io
.
newHttpClient
();
}
}
/// Sends an HTTP request and asynchronously returns the response.
@override
Future
<
StreamedResponse
>
send
(
BaseRequest
request
)
async
{
dynamic
stream
=
request
.
finalize
();
try
{
dynamic
ioRequest
=
await
_inner
.
openUrl
(
request
.
method
,
request
.
url
);
ioRequest
..
followRedirects
=
request
.
followRedirects
..
maxRedirects
=
request
.
maxRedirects
..
contentLength
=
request
.
contentLength
==
null
?
-
1
:
request
.
contentLength
..
persistentConnection
=
request
.
persistentConnection
;
request
.
headers
.
forEach
((
String
name
,
String
value
)
{
ioRequest
.
headers
.
set
(
name
,
value
);
});
dynamic
response
=
await
stream
.
pipe
(
DelegatingStreamConsumer
.
typed
(
ioRequest
));
Map
<
String
,
dynamic
>
headers
=
<
String
,
dynamic
>{};
response
.
headers
.
forEach
((
String
key
,
dynamic
values
)
{
headers
[
key
]
=
values
.
join
(
','
);
});
return
new
StreamedResponse
(
DelegatingStream
.
typed
/*<List<int>>*/
(
response
).
handleError
((
dynamic
error
)
=>
throw
new
ClientException
(
error
.
message
,
error
.
uri
),
test:
(
dynamic
error
)
=>
io
.
isHttpException
(
error
)),
response
.
statusCode
,
contentLength:
response
.
contentLength
==
-
1
?
null
:
response
.
contentLength
,
request:
request
,
headers:
headers
,
isRedirect:
response
.
isRedirect
,
persistentConnection:
response
.
persistentConnection
,
reasonPhrase:
response
.
reasonPhrase
);
}
catch
(
error
)
{
if
(!
io
.
isHttpException
(
error
))
rethrow
;
throw
new
ClientException
(
error
.
message
,
error
.
uri
);
}
}
/// Closes the client. This terminates all active connections. If a client
/// remains unclosed, the Dart process may not terminate.
@override
void
close
()
{
if
(
_inner
!=
null
)
_inner
.
close
(
force:
true
);
_inner
=
null
;
}
}
packages/flutter/lib/src/http/mock_client.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// 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
'dart:async'
;
import
'dart:typed_data'
;
import
'base_client.dart'
;
import
'base_request.dart'
;
import
'byte_stream.dart'
;
import
'request.dart'
;
import
'response.dart'
;
import
'streamed_response.dart'
;
// TODO(nweiz): once Dart has some sort of Rack- or WSGI-like standard for
// server APIs, MockClient should conform to it.
/// A mock HTTP client designed for use when testing code that uses
/// [BaseClient]. This client allows you to define a handler callback for all
/// requests that are made through it so that you can mock a server without
/// having to send real HTTP requests.
class
MockClient
extends
BaseClient
{
/// The handler for receiving [StreamedRequest]s and sending
/// [StreamedResponse]s.
final
MockClientStreamHandler
_handler
;
/// Creates a [MockClient] with a handler that receives [Request]s and sends
/// [Response]s.
MockClient
(
MockClientHandler
fn
)
:
this
.
_
((
BaseRequest
baseRequest
,
ByteStream
bodyStream
)
{
return
bodyStream
.
toBytes
().
then
((
Uint8List
bodyBytes
)
{
Request
request
=
new
Request
(
baseRequest
.
method
,
baseRequest
.
url
)
..
persistentConnection
=
baseRequest
.
persistentConnection
..
followRedirects
=
baseRequest
.
followRedirects
..
maxRedirects
=
baseRequest
.
maxRedirects
..
headers
.
addAll
(
baseRequest
.
headers
)
..
bodyBytes
=
bodyBytes
..
finalize
();
return
fn
(
request
);
}).
then
((
Response
response
)
{
return
new
StreamedResponse
(
new
ByteStream
.
fromBytes
(
response
.
bodyBytes
),
response
.
statusCode
,
contentLength:
response
.
contentLength
,
request:
baseRequest
,
headers:
response
.
headers
,
isRedirect:
response
.
isRedirect
,
persistentConnection:
response
.
persistentConnection
,
reasonPhrase:
response
.
reasonPhrase
);
});
});
MockClient
.
_
(
this
.
_handler
);
/// Creates a [MockClient] with a handler that receives [StreamedRequest]s and
/// sends [StreamedResponse]s.
MockClient
.
streaming
(
MockClientStreamHandler
fn
)
:
this
.
_
((
BaseRequest
request
,
ByteStream
bodyStream
)
{
return
fn
(
request
,
bodyStream
).
then
((
StreamedResponse
response
)
{
return
new
StreamedResponse
(
response
.
stream
,
response
.
statusCode
,
contentLength:
response
.
contentLength
,
request:
request
,
headers:
response
.
headers
,
isRedirect:
response
.
isRedirect
,
persistentConnection:
response
.
persistentConnection
,
reasonPhrase:
response
.
reasonPhrase
);
});
});
/// Sends a request.
@override
Future
<
StreamedResponse
>
send
(
BaseRequest
request
)
async
{
ByteStream
bodyStream
=
request
.
finalize
();
return
await
_handler
(
request
,
bodyStream
);
}
}
/// A handler function that receives [StreamedRequest]s and sends
/// [StreamedResponse]s. Note that [request] will be finalized.
typedef
Future
<
StreamedResponse
>
MockClientStreamHandler
(
BaseRequest
request
,
ByteStream
bodyStream
);
/// A handler function that receives [Request]s and sends [Response]s. Note that
/// [request] will be finalized.
typedef
Future
<
Response
>
MockClientHandler
(
BaseRequest
request
);
packages/flutter/lib/src/http/multipart_file.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// 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
'dart:async'
;
import
'dart:convert'
;
import
'package:async/async.dart'
;
import
'package:http_parser/http_parser.dart'
;
import
'package:path/path.dart'
as
path
;
import
'byte_stream.dart'
;
import
'io.dart'
as
io
;
import
'utils.dart'
;
/// A file to be uploaded as part of a [MultipartRequest]. This doesn't need to
/// correspond to a physical file.
class
MultipartFile
{
/// The name of the form field for the file.
final
String
field
;
/// The size of the file in bytes. This must be known in advance, even if this
/// file is created from a [ByteStream].
final
int
length
;
/// The basename of the file. May be null.
final
String
filename
;
/// The content-type of the file. Defaults to `application/octet-stream`.
final
MediaType
contentType
;
/// The stream that will emit the file's contents.
final
ByteStream
_stream
;
/// Creates a new [MultipartFile] from a chunked [Stream] of bytes. The length
/// of the file in bytes must be known in advance. If it's not, read the data
/// from the stream and use [MultipartFile.fromBytes] instead.
///
/// [contentType] currently defaults to `application/octet-stream`, but in the
/// future may be inferred from [filename].
MultipartFile
(
this
.
field
,
Stream
<
List
<
int
>>
stream
,
this
.
length
,
{
this
.
filename
,
MediaType
contentType
})
:
this
.
_stream
=
toByteStream
(
stream
),
this
.
contentType
=
contentType
!=
null
?
contentType
:
new
MediaType
(
"application"
,
"octet-stream"
);
/// Creates a new [MultipartFile] from a byte array.
///
/// [contentType] currently defaults to `application/octet-stream`, but in the
/// future may be inferred from [filename].
factory
MultipartFile
.
fromBytes
(
String
field
,
List
<
int
>
value
,
{
String
filename
,
MediaType
contentType
})
{
ByteStream
stream
=
new
ByteStream
.
fromBytes
(
value
);
return
new
MultipartFile
(
field
,
stream
,
value
.
length
,
filename:
filename
,
contentType:
contentType
);
}
/// Creates a new [MultipartFile] from a string.
///
/// The encoding to use when translating [value] into bytes is taken from
/// [contentType] if it has a charset set. Otherwise, it defaults to UTF-8.
/// [contentType] currently defaults to `text/plain; charset=utf-8`, but in
/// the future may be inferred from [filename].
factory
MultipartFile
.
fromString
(
String
field
,
String
value
,
{
String
filename
,
MediaType
contentType
})
{
contentType
=
contentType
==
null
?
new
MediaType
(
"text"
,
"plain"
)
:
contentType
;
Encoding
encoding
=
encodingForCharset
(
contentType
.
parameters
[
'charset'
],
UTF8
);
contentType
=
contentType
.
change
(
parameters:
<
String
,
String
>{
'charset'
:
encoding
.
name
});
return
new
MultipartFile
.
fromBytes
(
field
,
encoding
.
encode
(
value
),
filename:
filename
,
contentType:
contentType
);
}
/// Whether [finalize] has been called.
bool
get
isFinalized
=>
_isFinalized
;
bool
_isFinalized
=
false
;
// TODO(nweiz): Infer the content-type from the filename.
/// Creates a new [MultipartFile] from a path to a file on disk.
///
/// [filename] defaults to the basename of [filePath]. [contentType] currently
/// defaults to `application/octet-stream`, but in the future may be inferred
/// from [filename].
///
/// This can only be used in an environment that supports "dart:io".
static
Future
<
MultipartFile
>
fromPath
(
String
field
,
String
filePath
,
{
String
filename
,
MediaType
contentType
})
async
{
io
.
assertSupported
(
"MultipartFile.fromPath"
);
if
(
filename
==
null
)
filename
=
path
.
basename
(
filePath
);
dynamic
file
=
io
.
newFile
(
filePath
);
int
length
=
await
file
.
length
();
ByteStream
stream
=
new
ByteStream
(
DelegatingStream
.
typed
(
file
.
openRead
()));
return
new
MultipartFile
(
field
,
stream
,
length
,
filename:
filename
,
contentType:
contentType
);
}
// Finalizes the file in preparation for it being sent as part of a
// [MultipartRequest]. This returns a [ByteStream] that should emit the body
// of the file. The stream may be closed to indicate an empty file.
ByteStream
finalize
()
{
if
(
isFinalized
)
{
throw
new
StateError
(
"Can't finalize a finalized MultipartFile."
);
}
_isFinalized
=
true
;
return
_stream
;
}
}
packages/flutter/lib/src/http/multipart_request.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// 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
'dart:async'
;
import
'dart:convert'
;
import
'dart:math'
;
import
'base_request.dart'
;
import
'byte_stream.dart'
;
import
'multipart_file.dart'
;
import
'utils.dart'
;
final
RegExp
_newlineRegExp
=
new
RegExp
(
r"\r\n|\r|\n"
);
/// A `multipart/form-data` request. Such a request has both string [fields],
/// which function as normal form fields, and (potentially streamed) binary
/// [files].
///
/// This request automatically sets the Content-Type header to
/// `multipart/form-data`. This value will override any value set by the user.
///
/// var uri = Uri.parse("http://pub.dartlang.org/packages/create");
/// var request = new http.MultipartRequest("POST", url);
/// request.fields['user'] = 'nweiz@google.com';
/// request.files.add(new http.MultipartFile.fromFile(
/// 'package',
/// new File('build/package.tar.gz'),
/// contentType: new MediaType('application', 'x-tar'));
/// request.send().then((response) {
/// if (response.statusCode == 200) print("Uploaded!");
/// });
class
MultipartRequest
extends
BaseRequest
{
/// The total length of the multipart boundaries used when building the
/// request body. According to http://tools.ietf.org/html/rfc1341.html, this
/// can't be longer than 70.
static
const
int
_BOUNDARY_LENGTH
=
70
;
static
final
Random
_random
=
new
Random
();
/// The form fields to send for this request.
final
Map
<
String
,
String
>
fields
;
/// The private version of [files].
final
List
<
MultipartFile
>
_files
;
/// Creates a new [MultipartRequest].
MultipartRequest
(
String
method
,
Uri
url
)
:
fields
=
<
String
,
String
>{},
_files
=
<
MultipartFile
>[],
super
(
method
,
url
);
/// The list of files to upload for this request.
List
<
MultipartFile
>
get
files
=>
_files
;
/// The total length of the request body, in bytes. This is calculated from
/// [fields] and [files] and cannot be set manually.
@override
int
get
contentLength
{
int
length
=
0
;
fields
.
forEach
((
String
name
,
String
value
)
{
length
+=
"--"
.
length
+
_BOUNDARY_LENGTH
+
"
\r\n
"
.
length
+
UTF8
.
encode
(
_headerForField
(
name
,
value
)).
length
+
UTF8
.
encode
(
value
).
length
+
"
\r\n
"
.
length
;
});
for
(
MultipartFile
file
in
_files
)
{
length
+=
"--"
.
length
+
_BOUNDARY_LENGTH
+
"
\r\n
"
.
length
+
UTF8
.
encode
(
_headerForFile
(
file
)).
length
+
file
.
length
+
"
\r\n
"
.
length
;
}
return
length
+
"--"
.
length
+
_BOUNDARY_LENGTH
+
"--
\r\n
"
.
length
;
}
@override
set
contentLength
(
int
value
)
{
throw
new
UnsupportedError
(
"Cannot set the contentLength property of "
"multipart requests."
);
}
/// Freezes all mutable fields and returns a single-subscription [ByteStream]
/// that will emit the request body.
@override
ByteStream
finalize
()
{
// TODO(nweiz): freeze fields and files
String
boundary
=
_boundaryString
();
headers
[
'content-type'
]
=
'multipart/form-data; boundary="
$boundary
"'
;
super
.
finalize
();
StreamController
<
List
<
int
>>
controller
=
new
StreamController
<
List
<
int
>>(
sync:
true
);
void
writeAscii
(
String
string
)
{
controller
.
add
(
UTF8
.
encode
(
string
));
}
dynamic
writeUtf8
(
String
string
)
=>
controller
.
add
(
UTF8
.
encode
(
string
));
dynamic
writeLine
()
=>
controller
.
add
(<
int
>[
13
,
10
]);
// \r\n
fields
.
forEach
((
String
name
,
String
value
)
{
writeAscii
(
'--
$boundary
\r\n
'
);
writeAscii
(
_headerForField
(
name
,
value
));
writeUtf8
(
value
);
writeLine
();
});
Future
.
forEach
(
_files
,
(
MultipartFile
file
)
{
writeAscii
(
'--
$boundary
\r\n
'
);
writeAscii
(
_headerForFile
(
file
));
return
writeStreamToSink
(
file
.
finalize
(),
controller
)
.
then
((
_
)
=>
writeLine
());
}).
then
((
_
)
{
// TODO(nweiz): pass any errors propagated through this future on to
// the stream. See issue 3657.
writeAscii
(
'--
$boundary
--
\r\n
'
);
controller
.
close
();
});
return
new
ByteStream
(
controller
.
stream
);
}
/// All character codes that are valid in multipart boundaries. From
/// http://tools.ietf.org/html/rfc2046#section-5.1.1.
static
const
List
<
int
>
_BOUNDARY_CHARACTERS
=
const
<
int
>[
39
,
40
,
41
,
43
,
95
,
44
,
45
,
46
,
47
,
58
,
61
,
63
,
48
,
49
,
50
,
51
,
52
,
53
,
54
,
55
,
56
,
57
,
65
,
66
,
67
,
68
,
69
,
70
,
71
,
72
,
73
,
74
,
75
,
76
,
77
,
78
,
79
,
80
,
81
,
82
,
83
,
84
,
85
,
86
,
87
,
88
,
89
,
90
,
97
,
98
,
99
,
100
,
101
,
102
,
103
,
104
,
105
,
106
,
107
,
108
,
109
,
110
,
111
,
112
,
113
,
114
,
115
,
116
,
117
,
118
,
119
,
120
,
121
,
122
];
/// Returns the header string for a field. The return value is guaranteed to
/// contain only ASCII characters.
String
_headerForField
(
String
name
,
String
value
)
{
String
header
=
'content-disposition: form-data; name="
${_browserEncode(name)}
"'
;
if
(!
isPlainAscii
(
value
))
{
header
=
'
$header
\r\n
'
'content-type: text/plain; charset=utf-8
\r\n
'
'content-transfer-encoding: binary'
;
}
return
'
$header
\r\n\r\n
'
;
}
/// Returns the header string for a file. The return value is guaranteed to
/// contain only ASCII characters.
String
_headerForFile
(
MultipartFile
file
)
{
String
header
=
'content-type:
${file.contentType}
\r\n
'
'content-disposition: form-data; name="
${_browserEncode(file.field)}
"'
;
if
(
file
.
filename
!=
null
)
{
header
=
'
$header
; filename="
${_browserEncode(file.filename)}
"'
;
}
return
'
$header
\r\n\r\n
'
;
}
/// Encode [value] in the same way browsers do.
String
_browserEncode
(
String
value
)
{
// http://tools.ietf.org/html/rfc2388 mandates some complex encodings for
// field names and file names, but in practice user agents seem not to
// follow this at all. Instead, they URL-encode `\r`, `\n`, and `\r\n` as
// `\r\n`; URL-encode `"`; and do nothing else (even for `%` or non-ASCII
// characters). We follow their behavior.
return
value
.
replaceAll
(
_newlineRegExp
,
"%0D%0A"
).
replaceAll
(
'"'
,
"%22"
);
}
/// Returns a randomly-generated multipart boundary string
String
_boundaryString
()
{
String
prefix
=
"dart-http-boundary-"
;
List
<
int
>
list
=
new
List
<
int
>.
generate
(
_BOUNDARY_LENGTH
-
prefix
.
length
,
(
int
index
)
=>
_BOUNDARY_CHARACTERS
[
_random
.
nextInt
(
_BOUNDARY_CHARACTERS
.
length
)],
growable:
false
);
return
"
$prefix${new String.fromCharCodes(list)}
"
;
}
}
packages/flutter/lib/src/http/request.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// 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
'dart:convert'
;
import
'dart:typed_data'
;
import
'package:http_parser/http_parser.dart'
;
import
'base_request.dart'
;
import
'byte_stream.dart'
;
import
'utils.dart'
;
/// An HTTP request where the entire request body is known in advance.
class
Request
extends
BaseRequest
{
/// Creates a new HTTP request.
Request
(
String
method
,
Uri
url
)
:
_defaultEncoding
=
UTF8
,
_bodyBytes
=
new
Uint8List
(
0
),
super
(
method
,
url
);
/// The size of the request body, in bytes. This is calculated from
/// [bodyBytes].
///
/// The content length cannot be set for [Request], since it's automatically
/// calculated from [bodyBytes].
@override
int
get
contentLength
=>
bodyBytes
.
length
;
@override
set
contentLength
(
int
value
)
{
throw
new
UnsupportedError
(
"Cannot set the contentLength property of "
"non-streaming Request objects."
);
}
/// The default encoding to use when converting between [bodyBytes] and
/// [body]. This is only used if [encoding] hasn't been manually set and if
/// the content-type header has no encoding information.
Encoding
_defaultEncoding
;
/// The encoding used for the request. This encoding is used when converting
/// between [bodyBytes] and [body].
///
/// If the request has a `Content-Type` header and that header has a `charset`
/// parameter, that parameter's value is used as the encoding. Otherwise, if
/// [encoding] has been set manually, that encoding is used. If that hasn't
/// been set either, this defaults to [UTF8].
///
/// If the `charset` parameter's value is not a known [Encoding], reading this
/// will throw a [FormatException].
///
/// If the request has a `Content-Type` header, setting this will set the
/// charset parameter on that header.
Encoding
get
encoding
{
if
(
_contentType
==
null
||
!
_contentType
.
parameters
.
containsKey
(
'charset'
))
{
return
_defaultEncoding
;
}
return
requiredEncodingForCharset
(
_contentType
.
parameters
[
'charset'
]);
}
set
encoding
(
Encoding
value
)
{
_checkFinalized
();
_defaultEncoding
=
value
;
MediaType
contentType
=
_contentType
;
if
(
contentType
==
null
)
return
;
_contentType
=
contentType
.
change
(
parameters:
<
String
,
String
>{
'charset'
:
value
.
name
});
}
// TODO(nweiz): make this return a read-only view
/// The bytes comprising the body of the request. This is converted to and
/// from [body] using [encoding].
///
/// This list should only be set, not be modified in place.
Uint8List
get
bodyBytes
=>
_bodyBytes
;
Uint8List
_bodyBytes
;
set
bodyBytes
(
List
<
int
>
value
)
{
_checkFinalized
();
_bodyBytes
=
toUint8List
(
value
);
}
/// The body of the request as a string. This is converted to and from
/// [bodyBytes] using [encoding].
///
/// When this is set, if the request does not yet have a `Content-Type`
/// header, one will be added with the type `text/plain`. Then the `charset`
/// parameter of the `Content-Type` header (whether new or pre-existing) will
/// be set to [encoding] if it wasn't already set.
String
get
body
=>
encoding
.
decode
(
bodyBytes
);
set
body
(
String
value
)
{
bodyBytes
=
encoding
.
encode
(
value
);
MediaType
contentType
=
_contentType
;
if
(
contentType
==
null
)
{
_contentType
=
new
MediaType
(
"text"
,
"plain"
,
<
String
,
String
>{
'charset'
:
encoding
.
name
});
}
else
if
(!
contentType
.
parameters
.
containsKey
(
'charset'
))
{
_contentType
=
contentType
.
change
(
parameters:
<
String
,
String
>{
'charset'
:
encoding
.
name
});
}
}
/// The form-encoded fields in the body of the request as a map from field
/// names to values. The form-encoded body is converted to and from
/// [bodyBytes] using [encoding] (in the same way as [body]).
///
/// If the request doesn't have a `Content-Type` header of
/// `application/x-www-form-urlencoded`, reading this will throw a
/// [StateError].
///
/// If the request has a `Content-Type` header with a type other than
/// `application/x-www-form-urlencoded`, setting this will throw a
/// [StateError]. Otherwise, the content type will be set to
/// `application/x-www-form-urlencoded`.
///
/// This map should only be set, not modified in place.
Map
<
String
,
String
>
get
bodyFields
{
MediaType
contentType
=
_contentType
;
if
(
contentType
==
null
||
contentType
.
mimeType
!=
"application/x-www-form-urlencoded"
)
{
throw
new
StateError
(
'Cannot access the body fields of a Request without '
'content-type "application/x-www-form-urlencoded".'
);
}
return
Uri
.
splitQueryString
(
body
,
encoding:
encoding
);
}
set
bodyFields
(
Map
<
String
,
String
>
fields
)
{
MediaType
contentType
=
_contentType
;
if
(
contentType
==
null
)
{
_contentType
=
new
MediaType
(
"application"
,
"x-www-form-urlencoded"
);
}
else
if
(
contentType
.
mimeType
!=
"application/x-www-form-urlencoded"
)
{
throw
new
StateError
(
'Cannot set the body fields of a Request with '
'content-type "
${contentType.mimeType}
".'
);
}
this
.
body
=
mapToQuery
(
fields
,
encoding:
encoding
);
}
/// Freezes all mutable fields and returns a single-subscription [ByteStream]
/// containing the request body.
@override
ByteStream
finalize
()
{
super
.
finalize
();
return
new
ByteStream
.
fromBytes
(
bodyBytes
);
}
/// The `Content-Type` header of the request (if it exists) as a
/// [MediaType].
MediaType
get
_contentType
{
String
contentType
=
headers
[
'content-type'
];
if
(
contentType
==
null
)
return
null
;
return
new
MediaType
.
parse
(
contentType
);
}
set
_contentType
(
MediaType
value
)
{
headers
[
'content-type'
]
=
value
.
toString
();
}
/// Throw an error if this request has been finalized.
void
_checkFinalized
()
{
if
(!
finalized
)
return
;
throw
new
StateError
(
"Can't modify a finalized Request."
);
}
}
packages/flutter/lib/src/http/response.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// 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
'dart:async'
;
import
'dart:convert'
;
import
'dart:typed_data'
;
import
'package:http_parser/http_parser.dart'
;
import
'base_request.dart'
;
import
'base_response.dart'
;
import
'streamed_response.dart'
;
import
'utils.dart'
;
/// An HTTP response where the entire response body is known in advance.
class
Response
extends
BaseResponse
{
/// The bytes comprising the body of this response.
final
Uint8List
bodyBytes
;
/// Creates a new HTTP response with a string body.
Response
(
String
body
,
int
statusCode
,
{
BaseRequest
request
,
Map
<
String
,
String
>
headers:
const
<
String
,
String
>{},
bool
isRedirect:
false
,
bool
persistentConnection:
true
,
String
reasonPhrase
})
:
this
.
bytes
(
_encodingForHeaders
(
headers
).
encode
(
body
),
statusCode
,
request:
request
,
headers:
headers
,
isRedirect:
isRedirect
,
persistentConnection:
persistentConnection
,
reasonPhrase:
reasonPhrase
);
/// Create a new HTTP response with a byte array body.
Response
.
bytes
(
List
<
int
>
bodyBytes
,
int
statusCode
,
{
BaseRequest
request
,
Map
<
String
,
String
>
headers:
const
<
String
,
String
>{},
bool
isRedirect:
false
,
bool
persistentConnection:
true
,
String
reasonPhrase
})
:
bodyBytes
=
toUint8List
(
bodyBytes
),
super
(
statusCode
,
contentLength:
bodyBytes
.
length
,
request:
request
,
headers:
headers
,
isRedirect:
isRedirect
,
persistentConnection:
persistentConnection
,
reasonPhrase:
reasonPhrase
);
/// The body of the response as a string. This is converted from [bodyBytes]
/// using the `charset` parameter of the `Content-Type` header field, if
/// available. If it's unavailable or if the encoding name is unknown,
/// [LATIN1] is used by default, as per [RFC 2616][].
///
/// [RFC 2616]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html
String
get
body
=>
_encodingForHeaders
(
headers
).
decode
(
bodyBytes
);
/// Creates a new HTTP response by waiting for the full body to become
/// available from a [StreamedResponse].
static
Future
<
Response
>
fromStream
(
StreamedResponse
response
)
{
return
response
.
stream
.
toBytes
().
then
((
List
<
int
>
body
)
{
return
new
Response
.
bytes
(
body
,
response
.
statusCode
,
request:
response
.
request
,
headers:
response
.
headers
,
isRedirect:
response
.
isRedirect
,
persistentConnection:
response
.
persistentConnection
,
reasonPhrase:
response
.
reasonPhrase
);
});
}
}
/// Returns the encoding to use for a response with the given headers. This
/// defaults to [LATIN1] if the headers don't specify a charset or
/// if that charset is unknown.
Encoding
_encodingForHeaders
(
Map
<
String
,
String
>
headers
)
=>
encodingForCharset
(
_contentTypeForHeaders
(
headers
).
parameters
[
'charset'
]);
/// Returns the [MediaType] object for the given headers's content-type.
///
/// Defaults to `application/octet-stream`.
MediaType
_contentTypeForHeaders
(
Map
<
String
,
String
>
headers
)
{
String
contentType
=
headers
[
'content-type'
];
if
(
contentType
!=
null
)
return
new
MediaType
.
parse
(
contentType
);
return
new
MediaType
(
"application"
,
"octet-stream"
);
}
packages/flutter/lib/src/http/streamed_request.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// 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
'dart:async'
;
import
'byte_stream.dart'
;
import
'base_request.dart'
;
/// An HTTP request where the request body is sent asynchronously after the
/// connection has been established and the headers have been sent.
///
/// When the request is sent via [BaseClient.send], only the headers and
/// whatever data has already been written to [StreamedRequest.stream] will be
/// sent immediately. More data will be sent as soon as it's written to
/// [StreamedRequest.sink], and when the sink is closed the request will end.
class
StreamedRequest
extends
BaseRequest
{
/// Creates a new streaming request.
StreamedRequest
(
String
method
,
Uri
url
)
:
_controller
=
new
StreamController
<
List
<
int
>>(
sync:
true
),
super
(
method
,
url
);
/// The sink to which to write data that will be sent as the request body.
/// This may be safely written to before the request is sent; the data will be
/// buffered.
///
/// Closing this signals the end of the request.
EventSink
<
List
<
int
>>
get
sink
=>
_controller
.
sink
;
/// The controller for [sink], from which [BaseRequest] will read data for
/// [finalize].
final
StreamController
<
List
<
int
>>
_controller
;
/// Freezes all mutable fields other than [stream] and returns a
/// single-subscription [ByteStream] that emits the data being written to
/// [sink].
@override
ByteStream
finalize
()
{
super
.
finalize
();
return
new
ByteStream
(
_controller
.
stream
);
}
}
packages/flutter/lib/src/http/streamed_response.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// 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
'dart:async'
;
import
'byte_stream.dart'
;
import
'base_response.dart'
;
import
'base_request.dart'
;
import
'utils.dart'
;
/// An HTTP response where the response body is received asynchronously after
/// the headers have been received.
class
StreamedResponse
extends
BaseResponse
{
/// The stream from which the response body data can be read. This should
/// always be a single-subscription stream.
final
ByteStream
stream
;
/// Creates a new streaming response. [stream] should be a single-subscription
/// stream.
StreamedResponse
(
Stream
<
List
<
int
>>
stream
,
int
statusCode
,
{
int
contentLength
,
BaseRequest
request
,
Map
<
String
,
String
>
headers:
const
<
String
,
String
>
{},
bool
isRedirect:
false
,
bool
persistentConnection:
true
,
String
reasonPhrase
})
:
this
.
stream
=
toByteStream
(
stream
),
super
(
statusCode
,
contentLength:
contentLength
,
request:
request
,
headers:
headers
,
isRedirect:
isRedirect
,
persistentConnection:
persistentConnection
,
reasonPhrase:
reasonPhrase
);
}
packages/flutter/lib/src/http/utils.dart
deleted
100644 → 0
View file @
90774c18
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// 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
'dart:async'
;
import
'dart:convert'
;
import
'dart:typed_data'
;
import
'byte_stream.dart'
;
/// Converts a [Map] from parameter names to values to a URL query string.
///
/// mapToQuery({"foo": "bar", "baz": "bang"});
/// //=> "foo=bar&baz=bang"
String
mapToQuery
(
Map
<
String
,
String
>
map
,
{
Encoding
encoding
})
{
List
<
List
<
String
>>
pairs
=
<
List
<
String
>>[];
map
.
forEach
((
String
key
,
String
value
)
=>
pairs
.
add
(<
String
>[
Uri
.
encodeQueryComponent
(
key
,
encoding:
encoding
),
Uri
.
encodeQueryComponent
(
value
,
encoding:
encoding
)]));
return
pairs
.
map
((
List
<
String
>
pair
)
=>
"
${pair[0]}
=
${pair[1]}
"
).
join
(
"&"
);
}
/// Like [String.split], but only splits on the first occurrence of the pattern.
/// This will always return an array of two elements or fewer.
///
/// split1("foo,bar,baz", ","); //=> ["foo", "bar,baz"]
/// split1("foo", ","); //=> ["foo"]
/// split1("", ","); //=> []
List
<
String
>
split1
(
String
toSplit
,
String
pattern
)
{
if
(
toSplit
.
isEmpty
)
return
<
String
>[];
int
index
=
toSplit
.
indexOf
(
pattern
);
if
(
index
==
-
1
)
return
<
String
>[
toSplit
];
return
<
String
>[
toSplit
.
substring
(
0
,
index
),
toSplit
.
substring
(
index
+
pattern
.
length
)
];
}
/// Returns the [Encoding] that corresponds to [charset]. Returns [fallback] if
/// [charset] is null or if no [Encoding] was found that corresponds to
/// [charset].
Encoding
encodingForCharset
(
String
charset
,
[
Encoding
fallback
=
LATIN1
])
{
if
(
charset
==
null
)
return
fallback
;
Encoding
encoding
=
Encoding
.
getByName
(
charset
);
return
encoding
==
null
?
fallback
:
encoding
;
}
/// Returns the [Encoding] that corresponds to [charset]. Throws a
/// [FormatException] if no [Encoding] was found that corresponds to [charset].
/// [charset] may not be null.
Encoding
requiredEncodingForCharset
(
String
charset
)
{
Encoding
encoding
=
Encoding
.
getByName
(
charset
);
if
(
encoding
!=
null
)
return
encoding
;
throw
new
FormatException
(
'Unsupported encoding "
$charset
".'
);
}
/// A regular expression that matches strings that are composed entirely of
/// ASCII-compatible characters.
final
RegExp
_kAsciiOnly
=
new
RegExp
(
r"^[\x00-\x7F]+$"
);
/// Returns whether [string] is composed entirely of ASCII-compatible
/// characters.
bool
isPlainAscii
(
String
string
)
=>
_kAsciiOnly
.
hasMatch
(
string
);
/// Converts [input] into a [Uint8List].
///
/// If [input] is a [TypedData], this just returns a view on [input].
Uint8List
toUint8List
(
dynamic
input
)
{
if
(
input
is
Uint8List
)
return
input
;
if
(
input
is
TypedData
)
return
new
Uint8List
.
view
(
input
.
buffer
);
return
new
Uint8List
.
fromList
(
input
);
}
/// If [stream] is already a [ByteStream], returns it. Otherwise, wraps it in a
/// [ByteStream].
ByteStream
toByteStream
(
Stream
<
List
<
int
>>
stream
)
{
if
(
stream
is
ByteStream
)
return
stream
;
return
new
ByteStream
(
stream
);
}
/// Calls [onDone] once [stream] (a single-subscription [Stream]) is finished.
/// The return value, also a single-subscription [Stream] should be used in
/// place of [stream] after calling this method.
Stream
/*<T>*/
onDone
/*<T>*/
(
Stream
/*<T>*/
stream
,
void
onDone
())
=>
stream
.
transform
(
new
StreamTransformer
.
fromHandlers
(
handleDone:
(
EventSink
<
dynamic
>
sink
)
{
// ignore: always_specify_types
sink
.
close
();
onDone
();
}));
// TODO(nweiz): remove this when issue 7786 is fixed.
/// Pipes all data and errors from [stream] into [sink]. When [stream] is done,
/// [sink] is closed and the returned [Future] is completed.
Future
<
dynamic
>
store
(
Stream
<
dynamic
>
stream
,
EventSink
<
dynamic
>
sink
)
{
Completer
<
dynamic
>
completer
=
new
Completer
<
dynamic
>();
stream
.
listen
(
sink
.
add
,
onError:
sink
.
addError
,
onDone:
()
{
sink
.
close
();
completer
.
complete
();
});
return
completer
.
future
;
}
/// Pipes all data and errors from [stream] into [sink]. Completes [Future] once
/// [stream] is done. Unlike [store], [sink] remains open after [stream] is
/// done.
Future
<
dynamic
>
writeStreamToSink
(
Stream
<
dynamic
>
stream
,
EventSink
<
dynamic
>
sink
)
{
Completer
<
dynamic
>
completer
=
new
Completer
<
dynamic
>();
stream
.
listen
(
sink
.
add
,
onError:
sink
.
addError
,
onDone:
()
=>
completer
.
complete
());
return
completer
.
future
;
}
/// A pair of values.
class
Pair
<
E
,
F
>
{
E
first
;
F
last
;
Pair
(
this
.
first
,
this
.
last
);
@override
String
toString
()
=>
'(
$first
,
$last
)'
;
@override
bool
operator
==(
dynamic
other
)
{
if
(
other
is
!
Pair
)
return
false
;
return
other
.
first
==
first
&&
other
.
last
==
last
;
}
@override
int
get
hashCode
=>
first
.
hashCode
^
last
.
hashCode
;
}
/// Configures [future] so that its result (success or exception) is passed on
/// to [completer].
void
chainToCompleter
(
Future
<
dynamic
>
future
,
Completer
<
dynamic
>
completer
)
{
future
.
then
(
completer
.
complete
,
onError:
completer
.
completeError
);
}
packages/flutter/lib/src/services/asset_bundle.dart
View file @
68fb3e48
...
@@ -7,9 +7,10 @@ import 'dart:convert';
...
@@ -7,9 +7,10 @@ import 'dart:convert';
import
'dart:typed_data'
;
import
'dart:typed_data'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:
flutter
/http.dart'
as
http
;
import
'package:
http
/http.dart'
as
http
;
import
'platform_messages.dart'
;
import
'platform_messages.dart'
;
import
'http_client.dart'
;
/// A collection of resources used by the application.
/// A collection of resources used by the application.
///
///
...
@@ -84,15 +85,18 @@ abstract class AssetBundle {
...
@@ -84,15 +85,18 @@ abstract class AssetBundle {
class
NetworkAssetBundle
extends
AssetBundle
{
class
NetworkAssetBundle
extends
AssetBundle
{
/// Creates an network asset bundle that resolves asset keys as URLs relative
/// Creates an network asset bundle that resolves asset keys as URLs relative
/// to the given base URL.
/// to the given base URL.
NetworkAssetBundle
(
Uri
baseUrl
)
:
_baseUrl
=
baseUrl
;
NetworkAssetBundle
(
Uri
baseUrl
)
:
_baseUrl
=
baseUrl
,
_httpClient
=
createHttpClient
();
final
Uri
_baseUrl
;
final
Uri
_baseUrl
;
final
http
.
Client
_httpClient
;
String
_urlFromKey
(
String
key
)
=>
_baseUrl
.
resolve
(
key
).
toString
();
String
_urlFromKey
(
String
key
)
=>
_baseUrl
.
resolve
(
key
).
toString
();
@override
@override
Future
<
ByteData
>
load
(
String
key
)
async
{
Future
<
ByteData
>
load
(
String
key
)
async
{
final
http
.
Response
response
=
await
http
.
get
(
_urlFromKey
(
key
));
final
http
.
Response
response
=
await
_httpClient
.
get
(
_urlFromKey
(
key
));
if
(
response
.
statusCode
==
200
)
if
(
response
.
statusCode
==
200
)
return
null
;
return
null
;
return
response
.
bodyBytes
.
buffer
.
asByteData
();
return
response
.
bodyBytes
.
buffer
.
asByteData
();
...
@@ -100,7 +104,7 @@ class NetworkAssetBundle extends AssetBundle {
...
@@ -100,7 +104,7 @@ class NetworkAssetBundle extends AssetBundle {
@override
@override
Future
<
String
>
loadString
(
String
key
,
{
bool
cache:
true
})
async
{
Future
<
String
>
loadString
(
String
key
,
{
bool
cache:
true
})
async
{
final
http
.
Response
response
=
await
http
.
get
(
_urlFromKey
(
key
));
final
http
.
Response
response
=
await
_httpClient
.
get
(
_urlFromKey
(
key
));
return
response
.
statusCode
==
200
?
response
.
body
:
null
;
return
response
.
statusCode
==
200
?
response
.
body
:
null
;
}
}
...
...
packages/flutter/lib/src/services/http_client.dart
0 → 100644
View file @
68fb3e48
// 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.
import
'package:flutter/foundation.dart'
;
import
'package:http/http.dart'
as
http
;
/// Create a new [http.Client] object.
///
/// This can be set to a new function to override the default logic for creating
/// HTTP clients, for example so that all logic in the framework that triggers
/// HTTP requests will use the same `UserAgent` header, or so that tests can
/// provide an [http.MockClient].
ValueGetter
<
http
.
Client
>
createHttpClient
=
()
{
return
new
http
.
Client
();
};
packages/flutter/lib/src/services/image_provider.dart
View file @
68fb3e48
...
@@ -9,9 +9,10 @@ import 'dart:ui' as ui show Image;
...
@@ -9,9 +9,10 @@ import 'dart:ui' as ui show Image;
import
'dart:ui'
show
Size
,
Locale
,
hashValues
;
import
'dart:ui'
show
Size
,
Locale
,
hashValues
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:
flutter
/http.dart'
as
http
;
import
'package:
http
/http.dart'
as
http
;
import
'asset_bundle.dart'
;
import
'asset_bundle.dart'
;
import
'http_client.dart'
;
import
'image_cache.dart'
;
import
'image_cache.dart'
;
import
'image_decoder.dart'
;
import
'image_decoder.dart'
;
import
'image_stream.dart'
;
import
'image_stream.dart'
;
...
@@ -332,11 +333,13 @@ class NetworkImage extends ImageProvider<NetworkImage> {
...
@@ -332,11 +333,13 @@ class NetworkImage extends ImageProvider<NetworkImage> {
);
);
}
}
static
final
http
.
Client
_httpClient
=
createHttpClient
();
Future
<
ImageInfo
>
_loadAsync
(
NetworkImage
key
)
async
{
Future
<
ImageInfo
>
_loadAsync
(
NetworkImage
key
)
async
{
assert
(
key
==
this
);
assert
(
key
==
this
);
final
Uri
resolved
=
Uri
.
base
.
resolve
(
key
.
url
);
final
Uri
resolved
=
Uri
.
base
.
resolve
(
key
.
url
);
final
http
.
Response
response
=
await
http
.
get
(
resolved
);
final
http
.
Response
response
=
await
_httpClient
.
get
(
resolved
);
if
(
response
==
null
||
response
.
statusCode
!=
200
)
if
(
response
==
null
||
response
.
statusCode
!=
200
)
return
null
;
return
null
;
...
...
packages/flutter/pubspec.yaml
View file @
68fb3e48
...
@@ -6,15 +6,11 @@ homepage: http://flutter.io
...
@@ -6,15 +6,11 @@ homepage: http://flutter.io
dependencies
:
dependencies
:
collection
:
'
>=1.9.1
<2.0.0'
collection
:
'
>=1.9.1
<2.0.0'
http
:
'
>=0.11.3+11'
intl
:
'
>=0.14.0
<0.15.0'
intl
:
'
>=0.14.0
<0.15.0'
meta
:
^1.0.4
meta
:
^1.0.4
vector_math
:
'
>=2.0.3
<3.0.0'
vector_math
:
'
>=2.0.3
<3.0.0'
# async and http_parser can be removed when we move to using dart-lang/http
# directly.
async
:
"
^1.10.0"
http_parser
:
"
>=0.0.1
<4.0.0"
sky_engine
:
sky_engine
:
path
:
../../bin/cache/pkg/sky_engine
path
:
../../bin/cache/pkg/sky_engine
...
...
packages/flutter_test/lib/src/binding.dart
View file @
68fb3e48
...
@@ -8,10 +8,12 @@ import 'dart:ui' as ui;
...
@@ -8,10 +8,12 @@ import 'dart:ui' as ui;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/gestures.dart'
;
import
'package:flutter/http.dart'
as
http
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/scheduler.dart'
;
import
'package:flutter/scheduler.dart'
;
import
'package:flutter/services.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:http/http.dart'
as
http
;
import
'package:http/testing.dart'
as
http
;
import
'package:meta/meta.dart'
;
import
'package:meta/meta.dart'
;
import
'package:quiver/testing/async.dart'
;
import
'package:quiver/testing/async.dart'
;
import
'package:quiver/time.dart'
;
import
'package:quiver/time.dart'
;
...
@@ -119,7 +121,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
...
@@ -119,7 +121,7 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
@override
@override
void
initInstances
()
{
void
initInstances
()
{
timeDilation
=
1.0
;
// just in case the developer has artificially changed it for development
timeDilation
=
1.0
;
// just in case the developer has artificially changed it for development
http
.
Client
.
clientOverride
=
()
{
createHttpClient
=
()
{
return
new
http
.
MockClient
((
http
.
BaseRequest
request
)
{
return
new
http
.
MockClient
((
http
.
BaseRequest
request
)
{
return
new
Future
<
http
.
Response
>.
value
(
return
new
Future
<
http
.
Response
>.
value
(
new
http
.
Response
(
"Mocked: Unavailable."
,
404
,
request:
request
)
new
http
.
Response
(
"Mocked: Unavailable."
,
404
,
request:
request
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment