/*
- * Copyright 2020-2022 Soren Stoutner <soren@stoutner.com>.
+ * Copyright 2020-2023 Soren Stoutner <soren@stoutner.com>.
*
* This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
*
object UrlHelper {
// Content dispositions can contain other text besides the file name, and they can be in any order.
// Elements are separated by semicolons. Sometimes the file names are contained in quotes.
- @JvmStatic
fun getFileName(context: Context, contentDispositionString: String?, contentTypeString: String?, urlString: String): String {
// Define a file name string.
var fileNameString: String
return Pair(fileNameString, formattedFileSize)
}
- fun getSize(context: Context, url: URL, userAgent: String, cookiesEnabled: Boolean): String {
- // Initialize the formatted file size string.
- var formattedFileSize = context.getString(R.string.unknown_size)
-
- // Because everything relating to requesting data from a webserver can throw errors, the entire section must catch exceptions.
- try {
- // Instantiate the proxy helper.
- val proxyHelper = ProxyHelper()
-
- // Get the current proxy.
- val proxy = proxyHelper.getCurrentProxy(context)
-
- // Open a connection to the URL. No data is actually sent at this point.
- val httpUrlConnection = url.openConnection(proxy) as HttpURLConnection
-
- // Add the user agent to the header property.
- httpUrlConnection.setRequestProperty("User-Agent", userAgent)
-
- // Add the cookies if they are enabled.
- if (cookiesEnabled) {
- // Get the cookies for the current domain.
- val cookiesString = CookieManager.getInstance().getCookie(url.toString())
-
- // Only add the cookies if they are not null.
- if (cookiesString != null) {
- // Add the cookies to the header property.
- httpUrlConnection.setRequestProperty("Cookie", cookiesString)
- }
- }
-
- // 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.
- try {
- // Get the status code. This initiates a network connection.
- val responseCode = httpUrlConnection.responseCode
-
- // Check the response code.
- if (responseCode >= 400) { // The response code is an error message.
- // Set the formatted file size to indicate a bad URL.
- formattedFileSize = context.getString(R.string.invalid_url)
- } else { // The response code is not an error message.
- // Get the content length header.
- val contentLengthString = httpUrlConnection.getHeaderField("Content-Length")
-
- // Only process the content length string if it isn't null.
- if (contentLengthString != null) {
- // Convert the content length string to a long.
- val fileSize = contentLengthString.toLong()
-
- // Format the file size.
- formattedFileSize = NumberFormat.getInstance().format(fileSize) + " " + context.getString(R.string.bytes)
- }
- }
- } finally {
- // Disconnect the HTTP URL connection.
- httpUrlConnection.disconnect()
- }
- } catch (exception: Exception) {
- // Set the formatted file size to indicate a bad URL.
- formattedFileSize = context.getString(R.string.invalid_url)
- }
-
- // Return the formatted file size.
- return formattedFileSize
- }
-
- @JvmStatic
fun highlightSyntax(urlEditText: EditText, initialGrayColorSpan: ForegroundColorSpan, finalGrayColorSpan: ForegroundColorSpan, redColorSpan: ForegroundColorSpan) {
// Get the URL string.
val urlString: String = urlEditText.text.toString()
// Highlight the URL according to the protocol.
if (urlString.startsWith("file://") || urlString.startsWith("content://")) { // This is a file or content URL.
// De-emphasize everything before the file name.
- urlEditText.text.setSpan(initialGrayColorSpan, 0, urlString.lastIndexOf("/") + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
+ urlEditText.text.setSpan(initialGrayColorSpan, 0, urlString.lastIndexOf("/") + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
} else { // This is a web URL.
// Get the index of the `/` immediately after the domain name.
val endOfDomainName = urlString.indexOf("/", urlString.indexOf("//") + 2)
// Markup the beginning of the URL.
if (urlString.startsWith("http://")) { // The protocol is not encrypted.
// Highlight the protocol in red.
- urlEditText.text.setSpan(redColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
+ urlEditText.text.setSpan(redColorSpan, 0, 7, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
// De-emphasize subdomains.
if (penultimateDotIndex > 0) // There is more than one subdomain in the domain name.
- urlEditText.text.setSpan(initialGrayColorSpan, 7, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
- } else if (urlString.startsWith("https://")) { // The protocol is encrypted.
+ urlEditText.text.setSpan(initialGrayColorSpan, 7, penultimateDotIndex + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+ } else if (urlString.startsWith("https://") || urlString.startsWith("view-source:https://")) { // The protocol is encrypted.
// De-emphasize the protocol of connections that are encrypted.
if (penultimateDotIndex > 0) // There is more than one subdomain in the domain name. De-emphasize the protocol and the additional subdomains.
- urlEditText.text.setSpan(initialGrayColorSpan, 0, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
+ urlEditText.text.setSpan(initialGrayColorSpan, 0, penultimateDotIndex + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
else // There is only one subdomain in the domain name. De-emphasize only the protocol.
- urlEditText.text.setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
+ urlEditText.text.setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+ } else if (urlString.startsWith("view-source:http://")) { // An insecure source is being viewed.
+ // Check to see if subdomains should be de-emphasized.
+ if (penultimateDotIndex > 0) { // There are subdomains that should be de-emphasized.
+ // De-emphasize the `view-source:` text.
+ urlEditText.text.setSpan(initialGrayColorSpan, 0, penultimateDotIndex + 1, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+ } else { // There are no subdomains that need to be de-emphasized.
+ // De-emphasize the `view-source:` text.
+ urlEditText.text.setSpan(initialGrayColorSpan, 0, 11, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
+ }
+
+ // Highlight the protocol in red.
+ urlEditText.text.setSpan(redColorSpan, 12, 19, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
}
// De-emphasize the text after the domain name.