private void download()

in src/android/FileTransfer.java [660:882]


    private void download(final String source, final String target, JSONArray args, CallbackContext callbackContext) throws JSONException {
        LOG.d(LOG_TAG, "download " + source + " to " +  target);

        final CordovaResourceApi resourceApi = webView.getResourceApi();

        final String objectId = args.getString(3);
        final JSONObject headers = args.optJSONObject(4);

        final Uri sourceUri = resourceApi.remapUri(Uri.parse(source));
        int uriType = CordovaResourceApi.getUriType(sourceUri);
        final boolean useHttps = uriType == CordovaResourceApi.URI_TYPE_HTTPS;
        final boolean isLocalTransfer = !useHttps && uriType != CordovaResourceApi.URI_TYPE_HTTP;
        if (uriType == CordovaResourceApi.URI_TYPE_UNKNOWN) {
            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0, null);
            LOG.e(LOG_TAG, "Unsupported URI: " + sourceUri);
            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
            return;
        }

        Boolean shouldAllowRequest = null;
        if (isLocalTransfer) {
            shouldAllowRequest = true;
        }

        if (shouldAllowRequest == null) {
            try {
                Method gpm = webView.getClass().getMethod("getPluginManager");
                PluginManager pm = (PluginManager)gpm.invoke(webView);
                Method san = pm.getClass().getMethod("shouldAllowRequest", String.class);
                shouldAllowRequest = (Boolean)san.invoke(pm, source);
            } catch (NoSuchMethodException e) {
            } catch (IllegalAccessException e) {
            } catch (InvocationTargetException e) {
            }
        }

        if (!Boolean.TRUE.equals(shouldAllowRequest)) {
            LOG.w(LOG_TAG, "The Source URL is not in the Allow List: '" + source + "'");
            JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, null, 401, null);
            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
            return;
        }

        final RequestContext context = new RequestContext(source, target, callbackContext);
        synchronized (activeRequests) {
            activeRequests.put(objectId, context);
        }

        cordova.getThreadPool().execute(new Runnable() {
            public void run() {
                if (context.aborted) {
                    return;
                }

                // Accept a path or a URI for the source.
                Uri tmpTarget = Uri.parse(target);
                Uri targetUri = resourceApi.remapUri(
                        tmpTarget.getScheme() != null ? tmpTarget : Uri.fromFile(new File(target)));
                HttpURLConnection connection = null;
                File file = null;
                PluginResult result = null;
                TrackingInputStream inputStream = null;
                boolean cached = false;

                OutputStream outputStream = null;
                try {
                    OpenForReadResult readResult = null;

                    file = resourceApi.mapUriToFile(targetUri);
                    context.targetFile = file;

                    LOG.d(LOG_TAG, "Download file:" + sourceUri);

                    FileProgressResult progress = new FileProgressResult();

                    if (isLocalTransfer) {
                        readResult = resourceApi.openForRead(sourceUri);
                        if (readResult.length != -1) {
                            progress.setLengthComputable(true);
                            progress.setTotal(readResult.length);
                        }
                        inputStream = new SimpleTrackingInputStream(readResult.inputStream);
                    } else {
                        // connect to server
                        // Open a HTTP connection to the URL based on protocol
                        connection = resourceApi.createHttpConnection(sourceUri);
                        connection.setRequestMethod("GET");

                        // TODO: Make OkHttp use this CookieManager by default.
                        String cookie = getCookies(sourceUri.toString());

                        if(cookie != null)
                        {
                            connection.setRequestProperty("cookie", cookie);
                        }

                        // This must be explicitly set for gzip progress tracking to work.
                        connection.setRequestProperty("Accept-Encoding", "gzip");

                        // Handle the other headers
                        if (headers != null) {
                            addHeadersToRequest(connection, headers);
                        }

                        connection.connect();
                        if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) {
                            cached = true;
                            connection.disconnect();
                            LOG.d(LOG_TAG, "Resource not modified: " + source);
                            JSONObject error = createFileTransferError(NOT_MODIFIED_ERR, source, target, connection, null);
                            result = new PluginResult(PluginResult.Status.ERROR, error);
                        } else {
                            if (connection.getContentEncoding() == null || connection.getContentEncoding().equalsIgnoreCase("gzip")) {
                                // Only trust content-length header if we understand
                                // the encoding -- identity or gzip
                                if (connection.getContentLength() != -1) {
                                    progress.setLengthComputable(true);
                                    progress.setTotal(connection.getContentLength());
                                }
                            }
                            inputStream = getInputStream(connection);
                        }
                    }

                    if (!cached) {
                        try {
                            synchronized (context) {
                                if (context.aborted) {
                                    return;
                                }
                                context.connection = connection;
                            }

                            // write bytes to file
                            byte[] buffer = new byte[MAX_BUFFER_SIZE];
                            int bytesRead = 0;
                            outputStream = new FileOutputStream(file);
                            while ((bytesRead = inputStream.read(buffer)) > 0) {
                                outputStream.write(buffer, 0, bytesRead);
                                // Send a progress event.
                                progress.setLoaded(inputStream.getTotalRawBytesRead());
                                PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
                                progressResult.setKeepCallback(true);
                                context.sendPluginResult(progressResult);
                            }
                        } finally {
                            synchronized (context) {
                                context.connection = null;
                            }
                            safeClose(inputStream);
                            safeClose(outputStream);
                        }

                        LOG.d(LOG_TAG, "Saved file: " + target);


                        // create FileEntry object
                        Class webViewClass = webView.getClass();
                        PluginManager pm = null;
                        try {
                            Method gpm = webViewClass.getMethod("getPluginManager");
                            pm = (PluginManager) gpm.invoke(webView);
                        } catch (NoSuchMethodException e) {
                        } catch (IllegalAccessException e) {
                        } catch (InvocationTargetException e) {
                        }
                        if (pm == null) {
                            try {
                                Field pmf = webViewClass.getField("pluginManager");
                                pm = (PluginManager)pmf.get(webView);
                            } catch (NoSuchFieldException e) {
                            } catch (IllegalAccessException e) {
                            }
                        }
                        file = resourceApi.mapUriToFile(targetUri);
                        context.targetFile = file;
                        FileUtils filePlugin = (FileUtils) pm.getPlugin("File");
                        if (filePlugin != null) {
                            JSONObject fileEntry = filePlugin.getEntryForFile(file);
                            if (fileEntry != null) {
                                result = new PluginResult(PluginResult.Status.OK, fileEntry);
                            } else {
                                JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection, null);
                                LOG.e(LOG_TAG, "File plugin cannot represent download path");
                                result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
                            }
                        } else {
                            LOG.e(LOG_TAG, "File plugin not found; cannot save downloaded file");
                            result = new PluginResult(PluginResult.Status.ERROR, "File plugin not found; cannot save downloaded file");
                        }
                    }
                } catch (FileNotFoundException e) {
                    JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, connection, e);
                    LOG.e(LOG_TAG, error.toString(), e);
                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
                } catch (IOException e) {
                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection, e);
                    LOG.e(LOG_TAG, error.toString(), e);
                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
                } catch (JSONException e) {
                    LOG.e(LOG_TAG, e.getMessage(), e);
                    result = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
                } catch (Throwable e) {
                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection, e);
                    LOG.e(LOG_TAG, error.toString(), e);
                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
                } finally {
                    synchronized (activeRequests) {
                        activeRequests.remove(objectId);
                    }

                    if (result == null) {
                        result = new PluginResult(PluginResult.Status.ERROR, createFileTransferError(CONNECTION_ERR, source, target, connection, null));
                    }
                    // Remove incomplete download.
                    if (!cached && result.getStatus() != PluginResult.Status.OK.ordinal() && file != null) {
                        file.delete();
                    }
                    context.sendPluginResult(result);
                }
            }
        });
    }