Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(189)

Unified Diff: generated/googleapis_beta/lib/src/common_internal.dart

Issue 1078053002: Roll of googleapis as of 4/7/2015. (Closed) Base URL: https://github.com/dart-lang/googleapis.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: generated/googleapis_beta/lib/src/common_internal.dart
diff --git a/generated/googleapis_beta/lib/src/common_internal.dart b/generated/googleapis_beta/lib/src/common_internal.dart
deleted file mode 100644
index 06f5170b9f1f1e4688f7c73f35a7dc4395d0d9bc..0000000000000000000000000000000000000000
--- a/generated/googleapis_beta/lib/src/common_internal.dart
+++ /dev/null
@@ -1,921 +0,0 @@
-library googleapis_beta.common_internal;
-
-import "dart:async";
-import "dart:convert";
-import "dart:collection" as collection;
-
-import "package:crypto/crypto.dart" as crypto;
-import "../common/common.dart" as common_external;
-import "package:http/http.dart" as http;
-
-const String USER_AGENT_STRING =
- 'google-api-dart-client googleapis_beta/0.10.0';
-
-const CONTENT_TYPE_JSON_UTF8 = 'application/json; charset=utf-8';
-
-/**
- * Base class for all API clients, offering generic methods for
- * HTTP Requests to the API
- */
-class ApiRequester {
- final http.Client _httpClient;
- final String _rootUrl;
- final String _basePath;
-
- ApiRequester(this._httpClient, this._rootUrl, this._basePath) {
- assert(_rootUrl.endsWith('/'));
- }
-
-
- /**
- * Sends a HTTPRequest using [method] (usually GET or POST) to [requestUrl]
- * using the specified [urlParams] and [queryParams]. Optionally include a
- * [body] and/or [uploadMedia] in the request.
- *
- * If [uploadMedia] was specified [downloadOptions] must be
- * [DownloadOptions.Metadata] or `null`.
- *
- * If [downloadOptions] is [DownloadOptions.Metadata] the result will be
- * decoded as JSON.
- *
- * If [downloadOptions] is `null` the result will be a Future completing with
- * `null`.
- *
- * Otherwise the result will be downloaded as a [common_external.Media]
- */
- Future request(String requestUrl, String method,
- {String body, Map queryParams,
- common_external.Media uploadMedia,
- common_external.UploadOptions uploadOptions,
- common_external.DownloadOptions downloadOptions:
- common_external.DownloadOptions.Metadata}) {
- if (uploadMedia != null &&
- downloadOptions != common_external.DownloadOptions.Metadata) {
- throw new ArgumentError('When uploading a [Media] you cannot download a '
- '[Media] at the same time!');
- }
- common_external.ByteRange downloadRange;
- if (downloadOptions is common_external.PartialDownloadOptions &&
- !downloadOptions.isFullDownload) {
- downloadRange = downloadOptions.range;
- }
-
- return _request(requestUrl, method, body, queryParams,
- uploadMedia, uploadOptions,
- downloadOptions,
- downloadRange)
- .then(_validateResponse).then((http.StreamedResponse response) {
- if (downloadOptions == null) {
- // If no download options are given, the response is of no interest
- // and we will drain the stream.
- return response.stream.drain();
- } else if (downloadOptions == common_external.DownloadOptions.Metadata) {
- // Downloading JSON Metadata
- var stringStream = _decodeStreamAsText(response);
- if (stringStream != null) {
- return stringStream.join('').then((String bodyString) {
- if (bodyString == '') return null;
- return JSON.decode(bodyString);
- });
- } else {
- throw new common_external.ApiRequestError(
- "Unable to read response with content-type "
- "${response.headers['content-type']}.");
- }
- } else {
- // Downloading Media.
- var contentType = response.headers['content-type'];
- if (contentType == null) {
- throw new common_external.ApiRequestError(
- "No 'content-type' header in media response.");
- }
- var contentLength;
- try {
- contentLength = int.parse(response.headers['content-length']);
- } catch (_) {
- // We silently ignore errors here. If no content-length was specified
- // we use `null`.
- // Please note that the code below still asserts the content-length
- // is correct for range downloads.
- }
-
- if (downloadRange != null) {
- if (contentLength != downloadRange.length) {
- throw new common_external.ApiRequestError(
- "Content length of response does not match requested range "
- "length.");
- }
- var contentRange = response.headers['content-range'];
- var expected = 'bytes ${downloadRange.start}-${downloadRange.end}/';
- if (contentRange == null || !contentRange.startsWith(expected)) {
- throw new common_external.ApiRequestError("Attempting partial "
- "download but got invalid 'Content-Range' header "
- "(was: $contentRange, expected: $expected).");
- }
- }
-
- return new common_external.Media(
- response.stream, contentLength, contentType: contentType);
- }
- });
- }
-
- Future _request(String requestUrl, String method,
- String body, Map queryParams,
- common_external.Media uploadMedia,
- common_external.UploadOptions uploadOptions,
- common_external.DownloadOptions downloadOptions,
- common_external.ByteRange downloadRange) {
- bool downloadAsMedia =
- downloadOptions != null &&
- downloadOptions != common_external.DownloadOptions.Metadata;
-
- if (queryParams == null) queryParams = {};
-
- if (uploadMedia != null) {
- if (uploadOptions is common_external.ResumableUploadOptions) {
- queryParams['uploadType'] = const ['resumable'];
- } else if (body == null) {
- queryParams['uploadType'] = const ['media'];
- } else {
- queryParams['uploadType'] = const ['multipart'];
- }
- }
-
- if (downloadAsMedia) {
- queryParams['alt'] = const ['media'];
- } else if (downloadOptions != null) {
- queryParams['alt'] = const ['json'];
- }
-
- var path;
- if (requestUrl.startsWith('/')) {
- path ="$_rootUrl${requestUrl.substring(1)}";
- } else {
- path ="$_rootUrl${_basePath}$requestUrl";
- }
-
- bool containsQueryParameter = path.contains('?');
- addQueryParameter(String name, String value) {
- name = Escaper.escapeQueryComponent(name);
- value = Escaper.escapeQueryComponent(value);
- if (containsQueryParameter) {
- path = '$path&$name=$value';
- } else {
- path = '$path?$name=$value';
- }
- containsQueryParameter = true;
- }
- queryParams.forEach((String key, List<String> values) {
- for (var value in values) {
- addQueryParameter(key, value);
- }
- });
-
- var uri = Uri.parse(path);
-
- Future simpleUpload() {
- var bodyStream = uploadMedia.stream;
- var request = new RequestImpl(method, uri, bodyStream);
- request.headers.addAll({
- 'user-agent' : USER_AGENT_STRING,
- 'content-type' : uploadMedia.contentType,
- 'content-length' : '${uploadMedia.length}'
- });
- return _httpClient.send(request);
- }
-
- Future simpleRequest() {
- var length = 0;
- var bodyController = new StreamController<List<int>>();
- if (body != null) {
- var bytes = UTF8.encode(body);
- bodyController.add(bytes);
- length = bytes.length;
- }
- bodyController.close();
-
- var headers;
- if (downloadRange != null) {
- headers = {
- 'user-agent' : USER_AGENT_STRING,
- 'content-type' : CONTENT_TYPE_JSON_UTF8,
- 'content-length' : '$length',
- 'range' : 'bytes=${downloadRange.start}-${downloadRange.end}',
- };
- } else {
- headers = {
- 'user-agent' : USER_AGENT_STRING,
- 'content-type' : CONTENT_TYPE_JSON_UTF8,
- 'content-length' : '$length',
- };
- }
-
- var request = new RequestImpl(method, uri, bodyController.stream);
- request.headers.addAll(headers);
- return _httpClient.send(request);
- }
-
- if (uploadMedia != null) {
- // Three upload types:
- // 1. Resumable: Upload of data + metdata with multiple requests.
- // 2. Simple: Upload of media.
- // 3. Multipart: Upload of data + metadata.
-
- if (uploadOptions is common_external.ResumableUploadOptions) {
- var helper = new ResumableMediaUploader(
- _httpClient, uploadMedia, body, uri, method, uploadOptions);
- return helper.upload();
- }
-
- if (uploadMedia.length == null) {
- throw new ArgumentError(
- 'For non-resumable uploads you need to specify the length of the '
- 'media to upload.');
- }
-
- if (body == null) {
- return simpleUpload();
- } else {
- var uploader = new MultipartMediaUploader(
- _httpClient, uploadMedia, body, uri, method);
- return uploader.upload();
- }
- }
- return simpleRequest();
- }
-}
-
-
-/**
- * Does media uploads using the multipart upload protocol.
- */
-class MultipartMediaUploader {
- static final _boundary = '314159265358979323846';
- static final _base64Encoder = new Base64Encoder();
-
- final http.Client _httpClient;
- final common_external.Media _uploadMedia;
- final Uri _uri;
- final String _body;
- final String _method;
-
- MultipartMediaUploader(
- this._httpClient, this._uploadMedia, this._body, this._uri, this._method);
-
- Future<http.StreamedResponse> upload() {
- var base64MediaStream =
- _uploadMedia.stream.transform(_base64Encoder).transform(ASCII.encoder);
- var base64MediaStreamLength =
- Base64Encoder.lengthOfBase64Stream(_uploadMedia.length);
-
- // NOTE: We assume that [_body] is encoded JSON without any \r or \n in it.
- // This guarantees us that [_body] cannot contain a valid multipart
- // boundary.
- var bodyHead =
- '--$_boundary\r\n'
- "Content-Type: $CONTENT_TYPE_JSON_UTF8\r\n\r\n"
- + _body +
- '\r\n--$_boundary\r\n'
- "Content-Type: ${_uploadMedia.contentType}\r\n"
- "Content-Transfer-Encoding: base64\r\n\r\n";
- var bodyTail = '\r\n--$_boundary--';
-
- var totalLength =
- bodyHead.length + base64MediaStreamLength + bodyTail.length;
-
- var bodyController = new StreamController<List<int>>();
- bodyController.add(UTF8.encode(bodyHead));
- bodyController.addStream(base64MediaStream).then((_) {
- bodyController.add(UTF8.encode(bodyTail));
- }).catchError((error, stack) {
- bodyController.addError(error, stack);
- }).then((_) {
- bodyController.close();
- });
-
- var headers = {
- 'user-agent' : USER_AGENT_STRING,
- 'content-type' : "multipart/related; boundary=\"$_boundary\"",
- 'content-length' : '$totalLength'
- };
- var bodyStream = bodyController.stream;
- var request = new RequestImpl(_method, _uri, bodyStream);
- request.headers.addAll(headers);
- return _httpClient.send(request);
- }
-}
-
-
-/**
- * Base64 encodes a stream of bytes.
- */
-class Base64Encoder implements StreamTransformer<List<int>, String> {
- static int lengthOfBase64Stream(int lengthOfByteStream) {
- return ((lengthOfByteStream + 2) ~/ 3) * 4;
- }
-
- Stream<String> bind(Stream<List<int>> stream) {
- StreamController<String> controller;
-
- // Holds between 0 and 3 bytes and is used as a buffer.
- List<int> remainingBytes = [];
-
- void onData(List<int> bytes) {
- if ((remainingBytes.length + bytes.length) < 3) {
- remainingBytes.addAll(bytes);
- return;
- }
- int start;
- if (remainingBytes.length == 0) {
- start = 0;
- } else if (remainingBytes.length == 1) {
- remainingBytes.add(bytes[0]);
- remainingBytes.add(bytes[1]);
- start = 2;
- } else if (remainingBytes.length == 2) {
- remainingBytes.add(bytes[0]);
- start = 1;
- }
-
- // Convert & Send bytes from buffer (if necessary).
- if (remainingBytes.length > 0) {
- controller.add(crypto.CryptoUtils.bytesToBase64(remainingBytes));
- remainingBytes.clear();
- }
-
- int chunksOf3 = (bytes.length - start) ~/ 3;
- int end = start + 3 * chunksOf3;
- int remaining = bytes.length - end;
-
- // Convert & Send main bytes.
- if (start == 0 && end == bytes.length) {
- // Fast path if [bytes] are devisible by 3.
- controller.add(crypto.CryptoUtils.bytesToBase64(bytes));
- } else {
- controller.add(
- crypto.CryptoUtils.bytesToBase64(bytes.sublist(start, end)));
-
- // Buffer remaining bytes if necessary.
- if (end < bytes.length) {
- remainingBytes.addAll(bytes.sublist(end));
- }
- }
- }
-
- void onError(error, stack) {
- controller.addError(error, stack);
- }
-
- void onDone() {
- if (remainingBytes.length > 0) {
- controller.add(crypto.CryptoUtils.bytesToBase64(remainingBytes));
- remainingBytes.clear();
- }
- controller.close();
- }
-
- var subscription;
- controller = new StreamController<String>(
- onListen: () {
- subscription = stream.listen(
- onData, onError: onError, onDone: onDone);
- },
- onPause: () {
- subscription.pause();
- },
- onResume: () {
- subscription.resume();
- },
- onCancel: () {
- subscription.cancel();
- });
- return controller.stream;
- }
-}
-
-
-// TODO: Buffer less if we know the content length in advance.
-/**
- * Does media uploads using the resumable upload protocol.
- */
-class ResumableMediaUploader {
- final http.Client _httpClient;
- final common_external.Media _uploadMedia;
- final Uri _uri;
- final String _body;
- final String _method;
- final common_external.ResumableUploadOptions _options;
-
- ResumableMediaUploader(
- this._httpClient, this._uploadMedia, this._body, this._uri, this._method,
- this._options);
-
- /**
- * Returns the final [http.StreamedResponse] if the upload succeded and
- * completes with an error otherwise.
- *
- * The returned response stream has not been listened to.
- */
- Future<http.StreamedResponse> upload() {
- return _startSession().then((Uri uploadUri) {
- StreamSubscription subscription;
-
- var completer = new Completer<http.StreamedResponse>();
- bool completed = false;
-
- var chunkStack = new ChunkStack(_options.chunkSize);
- subscription = _uploadMedia.stream.listen((List<int> bytes) {
- chunkStack.addBytes(bytes);
-
- // Upload all but the last chunk.
- // The final send will be done in the [onDone] handler.
- bool hasPartialChunk = chunkStack.hasPartialChunk;
- if (chunkStack.length > 1 ||
- (chunkStack.length == 1 && hasPartialChunk)) {
- // Pause the input stream.
- subscription.pause();
-
- // Upload all chunks except the last one.
- var fullChunks;
- if (hasPartialChunk) {
- fullChunks = chunkStack.removeSublist(0, chunkStack.length);
- } else {
- fullChunks = chunkStack.removeSublist(0, chunkStack.length - 1);
- }
- Future.forEach(fullChunks,
- (c) => _uploadChunkDrained(uploadUri, c)).then((_) {
- // All chunks uploaded, we can continue consuming data.
- subscription.resume();
- }).catchError((error, stack) {
- subscription.cancel();
- completed = true;
- completer.completeError(error, stack);
- });
- }
- }, onError: (error, stack) {
- subscription.cancel();
- if (!completed) {
- completed = true;
- completer.completeError(error, stack);
- }
- }, onDone: () {
- if (!completed) {
- chunkStack.finalize();
-
- var lastChunk;
- if (chunkStack.length == 1) {
- lastChunk = chunkStack.removeSublist(0, chunkStack.length).first;
- } else {
- completer.completeError(new StateError(
- 'Resumable uploads need to result in at least one non-empty '
- 'chunk at the end.'));
- return;
- }
- var end = lastChunk.endOfChunk;
-
- // Validate that we have the correct number of bytes if length was
- // specified.
- if (_uploadMedia.length != null) {
- if (end < _uploadMedia.length) {
- completer.completeError(new common_external.ApiRequestError(
- 'Received less bytes than indicated by [Media.length].'));
- return;
- } else if (end > _uploadMedia.length) {
- completer.completeError(new common_external.ApiRequestError(
- 'Received more bytes than indicated by [Media.length].'));
- return;
- }
- }
-
- // Upload last chunk and *do not drain the response* but complete
- // with it.
- _uploadChunkResumable(uploadUri, lastChunk, lastChunk: true)
- .then((response) {
- completer.complete(response);
- }).catchError((error, stack) {
- completer.completeError(error, stack);
- });
- }
- });
-
- return completer.future;
- });
- }
-
- /**
- * Starts a resumable upload.
- *
- * Returns the [Uri] which should be used for uploading all content.
- */
- Future<Uri> _startSession() {
- var length = 0;
- var bytes;
- if (_body != null) {
- bytes = UTF8.encode(_body);
- length = bytes.length;
- }
- var bodyStream = _bytes2Stream(bytes);
-
- var request = new RequestImpl(_method, _uri, bodyStream);
- request.headers.addAll({
- 'user-agent' : USER_AGENT_STRING,
- 'content-type' : CONTENT_TYPE_JSON_UTF8,
- 'content-length' : '$length',
- 'x-upload-content-type' : _uploadMedia.contentType,
- 'x-upload-content-length' : '${_uploadMedia.length}',
- });
-
- return _httpClient.send(request).then((http.StreamedResponse response) {
- return response.stream.drain().then((_) {
- var uploadUri = response.headers['location'];
- if (response.statusCode != 200 || uploadUri == null) {
- throw new common_external.ApiRequestError(
- 'Invalid response for resumable upload attempt '
- '(status was: ${response.statusCode})');
- }
- return Uri.parse(uploadUri);
- });
- });
- }
-
- /**
- * Uploads [chunk], retries upon server errors. The response stream will be
- * drained.
- */
- Future _uploadChunkDrained(Uri uri, ResumableChunk chunk) {
- return _uploadChunkResumable(uri, chunk).then((response) {
- return response.stream.drain();
- });
- }
-
- /**
- * Does repeated attempts to upload [chunk].
- */
- Future _uploadChunkResumable(Uri uri,
- ResumableChunk chunk,
- {bool lastChunk: false}) {
- tryUpload(int attemptsLeft) {
- return _uploadChunk(uri, chunk, lastChunk: lastChunk)
- .then((http.StreamedResponse response) {
- var status = response.statusCode;
- if (attemptsLeft > 0 &&
- (status == 500 || (502 <= status && status < 504))) {
- return response.stream.drain().then((_) {
- // Delay the next attempt. Default backoff function is exponential.
- int failedAttemts = _options.numberOfAttempts - attemptsLeft;
- var duration = _options.backoffFunction(failedAttemts);
- if (duration == null) {
- throw new common_external.DetailedApiRequestError(
- status,
- 'Resumable upload: Uploading a chunk resulted in status '
- '$status. Maximum number of retries reached.');
- }
-
- return new Future.delayed(duration).then((_) {
- return tryUpload(attemptsLeft - 1);
- });
- });
- } else if (!lastChunk && status != 308) {
- return response.stream.drain().then((_) {
- throw new common_external.DetailedApiRequestError(
- status,
- 'Resumable upload: Uploading a chunk resulted in status '
- '$status instead of 308.');
- });
- } else if (lastChunk && status != 201 && status != 200) {
- return response.stream.drain().then((_) {
- throw new common_external.DetailedApiRequestError(
- status,
- 'Resumable upload: Uploading a chunk resulted in status '
- '$status instead of 200 or 201.');
- });
- } else {
- return response;
- }
- });
- }
-
- return tryUpload(_options.numberOfAttempts - 1);
- }
-
- /**
- * Uploads [length] bytes in [byteArrays] and ensures the upload was
- * successful.
- *
- * Content-Range: [start ... (start + length)[
- *
- * Returns the returned [http.StreamedResponse] or completes with an error if
- * the upload did not succeed. The response stream will not be listened to.
- */
- Future _uploadChunk(Uri uri, ResumableChunk chunk, {bool lastChunk: false}) {
- // If [uploadMedia.length] is null, we do not know the length.
- var mediaTotalLength = _uploadMedia.length;
- if (mediaTotalLength == null || lastChunk) {
- if (lastChunk) {
- mediaTotalLength = '${chunk.endOfChunk}';
- } else {
- mediaTotalLength = '*';
- }
- }
-
- var headers = {
- 'user-agent' : USER_AGENT_STRING,
- 'content-type' : _uploadMedia.contentType,
- 'content-length' : '${chunk.length}',
- 'content-range' :
- 'bytes ${chunk.offset}-${chunk.endOfChunk - 1}/$mediaTotalLength',
- };
-
- var stream = _listOfBytes2Stream(chunk.byteArrays);
- var request = new RequestImpl('PUT', uri, stream);
- request.headers.addAll(headers);
- return _httpClient.send(request);
- }
-
- Stream<List<int>> _bytes2Stream(List<int> bytes) {
- var bodyController = new StreamController<List<int>>();
- if (bytes != null) {
- bodyController.add(bytes);
- }
- bodyController.close();
- return bodyController.stream;
- }
-
- Stream<List<int>> _listOfBytes2Stream(List<List<int>> listOfBytes) {
- var controller = new StreamController();
- for (var array in listOfBytes) {
- controller.add(array);
- }
- controller.close();
- return controller.stream;
- }
-}
-
-
-/**
- * Represents a stack of [ResumableChunk]s.
- */
-class ChunkStack {
- final int _chunkSize;
- final List<ResumableChunk> _chunkStack = [];
-
- // Currently accumulated data.
- List<List<int>> _byteArrays = [];
- int _length = 0;
- int _offset = 0;
-
- bool _finalized = false;
-
- ChunkStack(this._chunkSize);
-
- /**
- * Whether data for a not-yet-finished [ResumableChunk] is present. A call to
- * `finalize` will create a [ResumableChunk] of this data.
- */
- bool get hasPartialChunk => _length > 0;
-
- /**
- * The number of chunks in this [ChunkStack].
- */
- int get length => _chunkStack.length;
-
- /**
- * The total number of bytes which have been converted to [ResumableChunk]s.
- * Can only be called once this [ChunkStack] has been finalized.
- */
- int get totalByteLength {
- if (!_finalized) {
- throw new StateError('ChunkStack has not been finalized yet.');
- }
-
- return _offset;
- }
-
- /**
- * Returns the chunks [from] ... [to] and deletes it from the stack.
- */
- List<ResumableChunk> removeSublist(int from, int to) {
- var sublist = _chunkStack.sublist(from, to);
- _chunkStack.removeRange(from, to);
- return sublist;
- }
-
- /**
- * Adds [bytes] to the buffer. If the buffer is larger than the given chunk
- * size a new [ResumableChunk] will be created.
- */
- void addBytes(List<int> bytes) {
- if (_finalized) {
- throw new StateError('ChunkStack has already been finalized.');
- }
-
- var remaining = _chunkSize - _length;
-
- if (bytes.length >= remaining) {
- var left = bytes.sublist(0, remaining);
- var right = bytes.sublist(remaining);
-
- _byteArrays.add(left);
- _length += left.length;
-
- _chunkStack.add(new ResumableChunk(_byteArrays, _offset, _length));
-
- _byteArrays = [];
- _offset += _length;
- _length = 0;
-
- addBytes(right);
- } else if (bytes.length > 0) {
- _byteArrays.add(bytes);
- _length += bytes.length;
- }
- }
-
- /**
- * Finalizes this [ChunkStack] and creates the last chunk (may have less bytes
- * than the chunk size, but not zero).
- */
- void finalize() {
- if (_finalized) {
- throw new StateError('ChunkStack has already been finalized.');
- }
- _finalized = true;
-
- if (_length > 0) {
- _chunkStack.add(new ResumableChunk(_byteArrays, _offset, _length));
- _offset += _length;
- }
- }
-}
-
-
-/**
- * Represents a chunk of data that will be transferred in one http request.
- */
-class ResumableChunk {
- final List<List<int>> byteArrays;
- final int offset;
- final int length;
-
- /**
- * Index of the next byte after this chunk.
- */
- int get endOfChunk => offset + length;
-
- ResumableChunk(this.byteArrays, this.offset, this.length);
-}
-
-class RequestImpl extends http.BaseRequest {
- final Stream<List<int>> _stream;
-
- RequestImpl(String method, Uri url, [Stream<List<int>> stream])
- : _stream = stream == null ? new Stream.fromIterable([]) : stream,
- super(method, url);
-
- http.ByteStream finalize() {
- super.finalize();
- return new http.ByteStream(_stream);
- }
-}
-
-
-class Escaper {
- // Character class definitions from RFC 6570
- // (see http://tools.ietf.org/html/rfc6570)
- // ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
- // DIGIT = %x30-39 ; 0
- // HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
- // pct-encoded = "%" HEXDIG HEXDIG
- // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- // reserved = gen-delims / sub-delims
- // gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
- // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
- // / "*" / "+" / "," / ";" / "="
-
- // NOTE: Uri.encodeQueryComponent() does the following:
- // ...
- // Then the resulting bytes are "percent-encoded". This transforms spaces
- // (U+0020) to a plus sign ('+') and all bytes that are not the ASCII decimal
- // digits, letters or one of '-._~' are written as a percent sign '%'
- // followed by the two-digit hexadecimal representation of the byte.
- // ...
-
- // NOTE: Uri.encodeFull() does the following:
- // ...
- // All characters except uppercase and lowercase letters, digits and the
- // characters !#$&'()*+,-./:;=?@_~ are percent-encoded.
- // ...
-
- static String ecapeVariableReserved(String name) {
- // ... perform variable expansion, as defined in Section 3.2.1, with the
- // allowed characters being those in the set
- // (unreserved / reserved / pct-encoded)
-
- // NOTE: The chracters [ and ] need (according to URI Template spec) not be
- // percent encoded. The dart implementation does percent-encode [ and ].
- // This gives us in effect a conservative encoding, since the server side
- // must interpret percent-encoded parts anyway due to arbitrary unicode.
-
- // NOTE: This is broken in the discovery protocol. It allows ? and & to be
- // expanded via URI Templates which may generate completely bogus URIs.
- // TODO/FIXME: Should we change this to _encodeUnreserved() as well
- // (disadvantage, slashes get encoded at this point)?
- return Uri.encodeFull(name);
- }
-
- static String ecapePathComponent(String name) {
- // For each defined variable in the variable-list, append "/" to the
- // result string and then perform variable expansion, as defined in
- // Section 3.2.1, with the allowed characters being those in the
- // *unreserved set*.
- return _encodeUnreserved(name);
- }
-
- static String ecapeVariable(String name) {
- // ... perform variable expansion, as defined in Section 3.2.1, with the
- // allowed characters being those in the *unreserved set*.
- return _encodeUnreserved(name);
- }
-
- static String escapeQueryComponent(String name) {
- // This method will not be used by UriTemplate, but rather for encoding
- // normal query name/value pairs.
-
- // NOTE: For safety reasons we use '%20' instead of '+' here as well.
- // TODO/FIXME: Should we do this?
- return _encodeUnreserved(name);
- }
-
- static String _encodeUnreserved(String name) {
- // The only difference between dart's [Uri.encodeQueryComponent] and the
- // encoding defined by RFC 6570 for the above-defined unreserved character
- // set is the encoding of space.
- // Dart's Uri class will convert spaces to '+' which we replace by '%20'.
- return Uri.encodeQueryComponent(name).replaceAll('+', '%20');
- }
-}
-
-
-Future<http.StreamedResponse> _validateResponse(
- http.StreamedResponse response) {
- var statusCode = response.statusCode;
-
- // TODO: We assume that status codes between [200..400[ are OK.
- // Can we assume this?
- if (statusCode < 200 || statusCode >= 400) {
- throwGeneralError() {
- throw new common_external.DetailedApiRequestError(
- statusCode, 'No error details. HTTP status was: ${statusCode}.');
- }
-
- // Some error happened, try to decode the response and fetch the error.
- Stream<String> stringStream = _decodeStreamAsText(response);
- if (stringStream != null) {
- return stringStream.transform(JSON.decoder).first.then((json) {
- if (json is Map && json['error'] is Map) {
- var error = json['error'];
- var code = error['code'];
- var message = error['message'];
- throw new common_external.DetailedApiRequestError(code, message);
- } else {
- throwGeneralError();
- }
- });
- } else {
- throwGeneralError();
- }
- }
-
- return new Future.value(response);
-}
-
-
-Stream<String> _decodeStreamAsText(http.StreamedResponse response) {
- // TODO: Correctly handle the response content-types, using correct
- // decoder.
- // Currently we assume that the api endpoint is responding with json
- // encoded in UTF8.
- String contentType = response.headers['content-type'];
- if (contentType != null &&
- contentType.toLowerCase().startsWith('application/json')) {
- return response.stream.transform(new Utf8Decoder(allowMalformed: true));
- } else {
- return null;
- }
-}
-
-Map mapMap(Map source, [Object convert(Object source) = null]) {
- assert(source != null);
- var result = new collection.LinkedHashMap();
- source.forEach((String key, value) {
- assert(key != null);
- if(convert == null) {
- result[key] = value;
- } else {
- result[key] = convert(value);
- }
- });
- return result;
-}
-
« no previous file with comments | « generated/googleapis_beta/lib/sqladmin/v1beta4.dart ('k') | generated/googleapis_beta/lib/taskqueue/v1beta2.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698