| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package com.taobao.weex.adapter; |
| |
| import android.support.annotation.NonNull; |
| import android.support.annotation.Nullable; |
| import android.text.TextUtils; |
| |
| import com.taobao.weex.common.WXRequest; |
| import com.taobao.weex.common.WXResponse; |
| |
| import java.io.BufferedReader; |
| import java.io.ByteArrayOutputStream; |
| import java.io.DataOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.net.HttpURLConnection; |
| import java.net.URL; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.Executors; |
| |
| |
| public class DefaultWXHttpAdapter implements IWXHttpAdapter { |
| |
| private static final IEventReporterDelegate DEFAULT_DELEGATE = new NOPEventReportDelegate(); |
| private ExecutorService mExecutorService; |
| |
| private void execute(Runnable runnable){ |
| if(mExecutorService==null){ |
| mExecutorService = Executors.newFixedThreadPool(3); |
| } |
| mExecutorService.execute(runnable); |
| } |
| |
| @Override |
| public void sendRequest(final WXRequest request, final OnHttpListener listener) { |
| if (listener != null) { |
| listener.onHttpStart(); |
| } |
| execute(new Runnable() { |
| @Override |
| public void run() { |
| WXResponse response = new WXResponse(); |
| IEventReporterDelegate reporter = getEventReporterDelegate(); |
| try { |
| HttpURLConnection connection = openConnection(request, listener); |
| reporter.preConnect(connection, request.body); |
| Map<String,List<String>> headers = connection.getHeaderFields(); |
| int responseCode = connection.getResponseCode(); |
| if(listener != null){ |
| listener.onHeadersReceived(responseCode,headers); |
| } |
| reporter.postConnect(); |
| |
| response.statusCode = String.valueOf(responseCode); |
| if (responseCode >= 200 && responseCode<=299) { |
| InputStream rawStream = connection.getInputStream(); |
| rawStream = reporter.interpretResponseStream(rawStream); |
| response.originalData = readInputStreamAsBytes(rawStream, listener); |
| } else { |
| response.errorMsg = readInputStream(connection.getErrorStream(), listener); |
| } |
| if (listener != null) { |
| listener.onHttpFinish(response); |
| } |
| } catch (IOException|IllegalArgumentException e) { |
| e.printStackTrace(); |
| response.statusCode = "-1"; |
| response.errorCode="-1"; |
| response.errorMsg=e.getMessage(); |
| if(listener!=null){ |
| listener.onHttpFinish(response); |
| } |
| if (e instanceof IOException) { |
| try { |
| reporter.httpExchangeFailed((IOException) e); |
| } catch (Throwable t) { |
| t.printStackTrace(); |
| } |
| } |
| } |
| } |
| }); |
| } |
| |
| |
| /** |
| * Opens an {@link HttpURLConnection} with parameters. |
| * |
| * @param request |
| * @param listener |
| * @return an open connection |
| * @throws IOException |
| */ |
| private HttpURLConnection openConnection(WXRequest request, OnHttpListener listener) throws IOException { |
| URL url = new URL(request.url); |
| HttpURLConnection connection = createConnection(url); |
| connection.setConnectTimeout(request.timeoutMs); |
| connection.setReadTimeout(request.timeoutMs); |
| connection.setUseCaches(false); |
| connection.setDoInput(true); |
| |
| if (request.paramMap != null) { |
| Set<String> keySets = request.paramMap.keySet(); |
| for (String key : keySets) { |
| connection.addRequestProperty(key, request.paramMap.get(key)); |
| } |
| } |
| |
| if ("POST".equals(request.method) || "PUT".equals(request.method) || "PATCH".equals(request.method)) { |
| connection.setRequestMethod(request.method); |
| if (request.body != null) { |
| if (listener != null) { |
| listener.onHttpUploadProgress(0); |
| } |
| connection.setDoOutput(true); |
| DataOutputStream out = new DataOutputStream(connection.getOutputStream()); |
| //TODO big stream will cause OOM; Progress callback is meaningless |
| out.write(request.body.getBytes()); |
| out.close(); |
| if (listener != null) { |
| listener.onHttpUploadProgress(100); |
| } |
| } |
| } else if (!TextUtils.isEmpty(request.method)) { |
| connection.setRequestMethod(request.method); |
| } else { |
| connection.setRequestMethod("GET"); |
| } |
| |
| return connection; |
| } |
| |
| private byte[] readInputStreamAsBytes(InputStream inputStream,OnHttpListener listener) throws IOException{ |
| if(inputStream == null){ |
| return null; |
| } |
| ByteArrayOutputStream buffer = new ByteArrayOutputStream(); |
| |
| int nRead; |
| int readCount = 0; |
| byte[] data = new byte[2048]; |
| |
| while ((nRead = inputStream.read(data, 0, data.length)) != -1) { |
| buffer.write(data, 0, nRead); |
| readCount += nRead; |
| if (listener != null) { |
| listener.onHttpResponseProgress(readCount); |
| } |
| } |
| |
| buffer.flush(); |
| |
| return buffer.toByteArray(); |
| } |
| |
| private String readInputStream(InputStream inputStream, OnHttpListener listener) throws IOException { |
| if(inputStream == null){ |
| return null; |
| } |
| StringBuilder builder = new StringBuilder(); |
| BufferedReader localBufferedReader = new BufferedReader(new InputStreamReader(inputStream)); |
| char[] data = new char[2048]; |
| int len; |
| while ((len = localBufferedReader.read(data)) != -1) { |
| builder.append(data, 0, len); |
| if (listener != null) { |
| listener.onHttpResponseProgress(builder.length()); |
| } |
| } |
| localBufferedReader.close(); |
| return builder.toString(); |
| } |
| |
| /** |
| * Create an {@link HttpURLConnection} for the specified {@code url}. |
| */ |
| protected HttpURLConnection createConnection(URL url) throws IOException { |
| return (HttpURLConnection) url.openConnection(); |
| } |
| |
| public @NonNull IEventReporterDelegate getEventReporterDelegate() { |
| return DEFAULT_DELEGATE; |
| } |
| |
| public interface IEventReporterDelegate { |
| void preConnect(HttpURLConnection connection, @Nullable String body); |
| void postConnect(); |
| InputStream interpretResponseStream(@Nullable InputStream inputStream); |
| void httpExchangeFailed(IOException e); |
| } |
| |
| private static class NOPEventReportDelegate implements IEventReporterDelegate { |
| @Override |
| public void preConnect(HttpURLConnection connection, @Nullable String body) { |
| //do nothing |
| } |
| |
| @Override |
| public void postConnect() { |
| //do nothing |
| } |
| |
| @Override |
| public InputStream interpretResponseStream(@Nullable InputStream inputStream) { |
| return inputStream; |
| } |
| |
| @Override |
| public void httpExchangeFailed(IOException e) { |
| //do nothing |
| } |
| } |
| } |