Use the Content-Disposition header to get file names for downloads. https://redmine...
[PrivacyBrowser.git] / app / src / main / java / com / stoutner / privacybrowser / asynctasks / GetUrlSize.java
1 /*
2  * Copyright © 2020 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
5  *
6  * Privacy Browser is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacybrowser.asynctasks;
21
22 import android.app.AlertDialog;
23 import android.content.Context;
24 import android.os.AsyncTask;
25 import android.webkit.CookieManager;
26 import android.widget.TextView;
27
28 import com.stoutner.privacybrowser.R;
29 import com.stoutner.privacybrowser.helpers.ProxyHelper;
30
31 import java.lang.ref.WeakReference;
32 import java.net.HttpURLConnection;
33 import java.net.Proxy;
34 import java.net.URL;
35 import java.text.NumberFormat;
36
37 public class GetUrlSize extends AsyncTask<String, Void, String> {
38     // Define weak references for the calling context and alert dialog.
39     private WeakReference<Context> contextWeakReference;
40     private WeakReference<AlertDialog> alertDialogWeakReference;
41
42     // Define the class variables.
43     private String userAgent;
44     private boolean cookiesEnabled;
45
46     // The public constructor.
47     public GetUrlSize(Context context, AlertDialog alertDialog, String userAgent, boolean cookiesEnabled) {
48         // Populate the week references for the context and alert dialog.
49         contextWeakReference = new WeakReference<>(context);
50         alertDialogWeakReference = new WeakReference<>(alertDialog);
51
52         // Store the class variables.
53         this.userAgent = userAgent;
54         this.cookiesEnabled = cookiesEnabled;
55     }
56
57     @Override
58     protected String doInBackground(String... urlToSave) {
59         // Get a handle for the context and the fragment.
60         Context context = contextWeakReference.get();
61         AlertDialog alertDialog = alertDialogWeakReference.get();
62
63         // Abort if the fragment is gone.
64         if (alertDialog == null) {
65             return null;
66         }
67
68         // Initialize the formatted file size string.
69         String formattedFileSize = context.getString(R.string.unknown_size);
70
71         // Because everything relating to requesting data from a webserver can throw errors, the entire section must catch exceptions.
72         try {
73             // Get the URL from the calling fragment.
74             URL url = new URL(urlToSave[0]);
75
76             // Instantiate the proxy helper.
77             ProxyHelper proxyHelper = new ProxyHelper();
78
79             // Get the current proxy.
80             Proxy proxy = proxyHelper.getCurrentProxy(context);
81
82             // Open a connection to the URL.  No data is actually sent at this point.
83             HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection(proxy);
84
85             // Add the user agent to the header property.
86             httpUrlConnection.setRequestProperty("User-Agent", userAgent);
87
88             // Add the cookies if they are enabled.
89             if (cookiesEnabled) {
90                 // Get the cookies for the current domain.
91                 String cookiesString = CookieManager.getInstance().getCookie(url.toString());
92
93                 // Only add the cookies if they are not null.
94                 if (cookiesString != null) {
95                     // Add the cookies to the header property.
96                     httpUrlConnection.setRequestProperty("Cookie", cookiesString);
97                 }
98             }
99
100             // The actual network request is in a `try` bracket so that `disconnect()` is run in the `finally` section even if an error is encountered in the main block.
101             try {
102                 // Exit if the task has been cancelled.
103                 if (isCancelled()) {
104                     // Disconnect the HTTP URL connection.
105                     httpUrlConnection.disconnect();
106
107                     // Return the formatted file size string.
108                     return formattedFileSize;
109                 }
110
111                 // Get the status code.  This initiates a network connection.
112                 int responseCode = httpUrlConnection.getResponseCode();
113
114                 // Exit if the task has been cancelled.
115                 if (isCancelled()) {
116                     // Disconnect the HTTP URL connection.
117                     httpUrlConnection.disconnect();
118
119                     // Return the formatted file size string.
120                     return formattedFileSize;
121                 }
122
123                 // Check the response code.
124                 if (responseCode >= 400) {  // The response code is an error message.
125                     // Set the formatted file size to indicate a bad URL.
126                     formattedFileSize = context.getString(R.string.invalid_url);
127                 } else {  // The response code is not an error message.
128                     // Get the content length header.
129                     String contentLengthString = httpUrlConnection.getHeaderField("Content-Length");
130
131                     // Only process the content length string if it isn't null.
132                     if (contentLengthString != null) {
133                         // Convert the content length string to a long.
134                         long fileSize = Long.parseLong(contentLengthString);
135
136                         // Format the file size.
137                         formattedFileSize = NumberFormat.getInstance().format(fileSize) + " " + context.getString(R.string.bytes);
138                     }
139                 }
140             } finally {
141                 // Disconnect the HTTP URL connection.
142                 httpUrlConnection.disconnect();
143             }
144         } catch (Exception exception) {
145             // Set the formatted file size to indicate a bad URL.
146             formattedFileSize = context.getString(R.string.invalid_url);
147         }
148
149         // Return the formatted file size string.
150         return formattedFileSize;
151     }
152
153     // `onPostExecute()` operates on the UI thread.
154     @Override
155     protected void onPostExecute(String fileSize) {
156         // Get a handle for the alert dialog.
157         AlertDialog alertDialog = alertDialogWeakReference.get();
158
159         // Abort if the alert dialog is gone.
160         if (alertDialog == null) {
161             return;
162         }
163
164         // Get a handle for the file size text view.
165         TextView fileSizeTextView = alertDialog.findViewById(R.id.file_size_textview);
166
167         // Update the file size.
168         fileSizeTextView.setText(fileSize);
169     }
170 }