mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add an implementation of url_loader.mojom using OkHttp
This CL is the beginnings of an implementation of url_loader.mojom using the OkHttp library. OkHttp is a relatively simple HTTP client library for Android that implements HTTP/1.1 and HTTP/2.0. We might want to use OkHttp to bootstrap into a more full-featured network_service implementation based on //net. R=jamesr@chromium.org Review URL: https://codereview.chromium.org/930673002
This commit is contained in:
parent
f9ddb1cabd
commit
cf2f7afb9f
21
services/oknet/BUILD.gn
Normal file
21
services/oknet/BUILD.gn
Normal file
@ -0,0 +1,21 @@
|
||||
# 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.
|
||||
|
||||
import("//build/config/android/config.gni")
|
||||
import("//build/config/android/rules.gni")
|
||||
|
||||
android_library("oknet") {
|
||||
java_files = [
|
||||
"src/org/domokit/oknet/NetworkServiceImpl.java",
|
||||
"src/org/domokit/oknet/UrlLoaderImpl.java",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"//mojo/public/java:bindings",
|
||||
"//mojo/public/java:system",
|
||||
"//mojo/services/network/public/interfaces:interfaces_java",
|
||||
"//third_party/okhttp",
|
||||
"//third_party/okhttp:okio",
|
||||
]
|
||||
}
|
||||
76
services/oknet/src/org/domokit/oknet/NetworkServiceImpl.java
Normal file
76
services/oknet/src/org/domokit/oknet/NetworkServiceImpl.java
Normal file
@ -0,0 +1,76 @@
|
||||
// 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.
|
||||
|
||||
package org.domokit.oknet;
|
||||
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
|
||||
import org.chromium.mojo.bindings.InterfaceRequest;
|
||||
import org.chromium.mojo.system.Core;
|
||||
import org.chromium.mojo.system.DataPipe;
|
||||
import org.chromium.mojo.system.MojoException;
|
||||
import org.chromium.mojom.mojo.CookieStore;
|
||||
import org.chromium.mojom.mojo.NetAddress;
|
||||
import org.chromium.mojom.mojo.NetworkService;
|
||||
import org.chromium.mojom.mojo.TcpBoundSocket;
|
||||
import org.chromium.mojom.mojo.TcpConnectedSocket;
|
||||
import org.chromium.mojom.mojo.UdpSocket;
|
||||
import org.chromium.mojom.mojo.UrlLoader;
|
||||
import org.chromium.mojom.mojo.WebSocket;
|
||||
|
||||
/**
|
||||
* OkHttp implementation of NetworkService.
|
||||
*/
|
||||
public class NetworkServiceImpl implements NetworkService {
|
||||
private OkHttpClient mClient;
|
||||
private Core mCore;
|
||||
|
||||
public NetworkServiceImpl(Core core) {
|
||||
assert core != null;
|
||||
mCore = core;
|
||||
mClient = new OkHttpClient();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
@Override
|
||||
public void onConnectionError(MojoException e) {}
|
||||
|
||||
@Override
|
||||
public void createUrlLoader(InterfaceRequest<UrlLoader> loader) {
|
||||
UrlLoader.MANAGER.bind(new UrlLoaderImpl(mCore, mClient), loader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getCookieStore(InterfaceRequest<CookieStore> cookieStore) {
|
||||
cookieStore.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createWebSocket(InterfaceRequest<WebSocket> socket) {
|
||||
socket.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTcpBoundSocket(NetAddress localAddress,
|
||||
InterfaceRequest<TcpBoundSocket> boundSocket, CreateTcpBoundSocketResponse callback) {
|
||||
boundSocket.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createTcpConnectedSocket(NetAddress remoteAddress,
|
||||
DataPipe.ConsumerHandle sendStream, DataPipe.ProducerHandle receiveStream,
|
||||
InterfaceRequest<TcpConnectedSocket> clientSocket,
|
||||
CreateTcpConnectedSocketResponse callback) {
|
||||
sendStream.close();
|
||||
receiveStream.close();
|
||||
clientSocket.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createUdpSocket(InterfaceRequest<UdpSocket> socket) {
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
196
services/oknet/src/org/domokit/oknet/UrlLoaderImpl.java
Normal file
196
services/oknet/src/org/domokit/oknet/UrlLoaderImpl.java
Normal file
@ -0,0 +1,196 @@
|
||||
// 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.
|
||||
|
||||
package org.domokit.oknet;
|
||||
|
||||
import com.squareup.okhttp.Call;
|
||||
import com.squareup.okhttp.Callback;
|
||||
import com.squareup.okhttp.Headers;
|
||||
import com.squareup.okhttp.MediaType;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
import com.squareup.okhttp.ResponseBody;
|
||||
|
||||
import org.chromium.mojo.system.AsyncWaiter;
|
||||
import org.chromium.mojo.system.Core;
|
||||
import org.chromium.mojo.system.DataPipe;
|
||||
import org.chromium.mojo.system.MojoException;
|
||||
import org.chromium.mojo.system.MojoResult;
|
||||
import org.chromium.mojo.system.Pair;
|
||||
import org.chromium.mojom.mojo.NetworkError;
|
||||
import org.chromium.mojom.mojo.UrlLoader;
|
||||
import org.chromium.mojom.mojo.UrlLoaderStatus;
|
||||
import org.chromium.mojom.mojo.UrlRequest;
|
||||
import org.chromium.mojom.mojo.UrlResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import okio.BufferedSource;
|
||||
|
||||
/**
|
||||
* OkHttp implementation of UrlLoader.
|
||||
*/
|
||||
public class UrlLoaderImpl implements UrlLoader {
|
||||
private Core mCore;
|
||||
private OkHttpClient mClient;
|
||||
private boolean mIsLoading;
|
||||
private NetworkError mError;
|
||||
|
||||
class CopyToPipeJob {
|
||||
private BufferedSource mSource;
|
||||
private DataPipe.ProducerHandle mProducer;
|
||||
|
||||
public CopyToPipeJob(BufferedSource source, DataPipe.ProducerHandle producerHandle) {
|
||||
mSource = source;
|
||||
mProducer = producerHandle;
|
||||
}
|
||||
|
||||
public void copy() throws IOException {
|
||||
int result = 0;
|
||||
do {
|
||||
try {
|
||||
ByteBuffer buffer = mProducer.beginWriteData(0, DataPipe.WriteFlags.none());
|
||||
// TODO(abarth): There must be a way to do this without the temporary buffer.
|
||||
byte[] tmp = new byte[buffer.capacity()];
|
||||
result = mSource.read(tmp);
|
||||
buffer.put(tmp);
|
||||
mProducer.endWriteData(result == -1 ? 0 : result);
|
||||
} catch (MojoException e) {
|
||||
if (e.getMojoResult() != MojoResult.SHOULD_WAIT) throw e;
|
||||
copyMoreAsync();
|
||||
return;
|
||||
}
|
||||
} while (result != -1);
|
||||
|
||||
mIsLoading = false;
|
||||
mProducer.close();
|
||||
}
|
||||
|
||||
private void copyMoreAsync() {
|
||||
AsyncWaiter w = mCore.getDefaultAsyncWaiter();
|
||||
w.asyncWait(mProducer, Core.HandleSignals.WRITABLE, -1, new AsyncWaiter.Callback() {
|
||||
@Override
|
||||
public void onResult(int result) {
|
||||
assert result == MojoResult.OK;
|
||||
try {
|
||||
copy();
|
||||
} catch (IOException e) {
|
||||
mIsLoading = false;
|
||||
mProducer.close();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onError(MojoException exception) {
|
||||
mIsLoading = false;
|
||||
mProducer.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public UrlLoaderImpl(Core core, OkHttpClient client) {
|
||||
assert core != null;
|
||||
mCore = core;
|
||||
mClient = client;
|
||||
mIsLoading = false;
|
||||
mError = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
@Override
|
||||
public void onConnectionError(MojoException e) {}
|
||||
|
||||
@Override
|
||||
public void start(UrlRequest request, StartResponse callback) {
|
||||
mIsLoading = true;
|
||||
mError = null;
|
||||
|
||||
Request.Builder builder =
|
||||
new Request.Builder().url(request.url).method(request.method, null);
|
||||
|
||||
if (request.headers != null) {
|
||||
for (String header : request.headers) {
|
||||
String[] parts = header.split(":");
|
||||
String name = parts[0].trim();
|
||||
String value = parts.length > 1 ? parts[2].trim() : "";
|
||||
builder.addHeader(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(abarth): body, responseBodyBufferSize, autoFollowRedirects, bypassCache.
|
||||
final StartResponse responseCallback = callback;
|
||||
Call call = mClient.newCall(builder.build());
|
||||
call.enqueue(new Callback() {
|
||||
@Override
|
||||
public void onFailure(Request request, IOException e) {
|
||||
mError = new NetworkError();
|
||||
// TODO(abarth): Which mError.code should we set?
|
||||
mError.description = e.toString();
|
||||
UrlResponse urlResponse = new UrlResponse();
|
||||
urlResponse.error = mError;
|
||||
responseCallback.call(urlResponse);
|
||||
|
||||
mIsLoading = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Response response) {
|
||||
UrlResponse urlResponse = new UrlResponse();
|
||||
urlResponse.url = response.request().urlString();
|
||||
urlResponse.statusCode = response.code();
|
||||
urlResponse.statusLine = response.message();
|
||||
|
||||
Headers headers = response.headers();
|
||||
urlResponse.headers = new String[headers.size()];
|
||||
for (int i = 0; i < headers.size(); ++i) {
|
||||
String name = headers.name(i);
|
||||
String value = headers.value(i);
|
||||
urlResponse.headers[i] = name + ": " + value;
|
||||
}
|
||||
|
||||
ResponseBody body = response.body();
|
||||
MediaType mediaType = body.contentType();
|
||||
if (mediaType != null) {
|
||||
urlResponse.mimeType = mediaType.type() + "/" + mediaType.subtype();
|
||||
Charset charset = mediaType.charset();
|
||||
if (charset != null)
|
||||
urlResponse.charset = charset.displayName();
|
||||
}
|
||||
|
||||
Pair<DataPipe.ProducerHandle, DataPipe.ConsumerHandle> handles =
|
||||
mCore.createDataPipe(null);
|
||||
DataPipe.ProducerHandle producerHandle = handles.first;
|
||||
DataPipe.ConsumerHandle consumerHandle = handles.second;
|
||||
urlResponse.body = consumerHandle;
|
||||
responseCallback.call(urlResponse);
|
||||
CopyToPipeJob job = new CopyToPipeJob(body.source(), producerHandle);
|
||||
try {
|
||||
job.copy();
|
||||
} catch (IOException e) {
|
||||
mIsLoading = false;
|
||||
producerHandle.close();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void followRedirect(FollowRedirectResponse callback) {
|
||||
// TODO(abarth): Implement redirects.
|
||||
callback.call(new UrlResponse());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queryStatus(QueryStatusResponse callback) {
|
||||
UrlLoaderStatus status = new UrlLoaderStatus();
|
||||
status.error = mError;
|
||||
status.isLoading = mIsLoading;
|
||||
callback.call(status);
|
||||
}
|
||||
}
|
||||
@ -85,6 +85,7 @@ android_library("java") {
|
||||
"//mojo/public/java:bindings",
|
||||
"//mojo/public/java:system",
|
||||
"//mojo/services/network/public/interfaces:interfaces_java",
|
||||
"//sky/services/oknet",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,9 @@ import org.chromium.mojo.system.MessagePipeHandle;
|
||||
import org.chromium.mojo.system.MojoException;
|
||||
import org.chromium.mojo.system.Pair;
|
||||
import org.chromium.mojo.system.impl.CoreImpl;
|
||||
import org.chromium.mojom.mojo.NetworkService;
|
||||
import org.chromium.mojom.mojo.ServiceProvider;
|
||||
import org.domokit.oknet.NetworkServiceImpl;
|
||||
|
||||
/**
|
||||
* A class to intialize the network.
|
||||
@ -42,6 +44,10 @@ public class JavaServiceProvider implements ServiceProvider {
|
||||
|
||||
@Override
|
||||
public void connectToService(String interfaceName, MessagePipeHandle pipe) {
|
||||
if (interfaceName.equals(NetworkService.MANAGER.getName())) {
|
||||
NetworkService.MANAGER.bind(new NetworkServiceImpl(mCore), pipe);
|
||||
return;
|
||||
}
|
||||
pipe.close();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user