214 lines
8.2 KiB
Kotlin
214 lines
8.2 KiB
Kotlin
/*
|
|
* Copyright 2017 Hippo Seven
|
|
*
|
|
* Licensed 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.hippo.network
|
|
|
|
import android.content.ContentValues
|
|
import android.content.Context
|
|
import android.database.Cursor
|
|
import android.database.sqlite.SQLiteDatabase
|
|
import android.database.sqlite.SQLiteOpenHelper
|
|
import android.util.Log
|
|
import com.hippo.database.MSQLiteBuilder
|
|
import com.hippo.util.SqlUtils
|
|
import okhttp3.Cookie
|
|
|
|
internal class CookieDatabase(context: Context, name: String) {
|
|
private val cookieIdMap: MutableMap<Cookie, Long> = HashMap()
|
|
private val helper: SQLiteOpenHelper
|
|
private val db: SQLiteDatabase
|
|
|
|
val allCookies: MutableMap<String, CookieSet>
|
|
get() {
|
|
val now = System.currentTimeMillis()
|
|
val map: MutableMap<String, CookieSet> = HashMap()
|
|
val toRemove: MutableList<Long> = ArrayList()
|
|
db.rawQuery("SELECT * FROM $TABLE_COOKIE;", null).use { cursor ->
|
|
while (cursor.moveToNext()) {
|
|
val id = SqlUtils.getLong(cursor, COLUMN_ID, 0)
|
|
val cookie = getCookie(cursor, now)
|
|
if (cookie != null) {
|
|
// Save id of the cookie in db
|
|
cookieIdMap[cookie] = id
|
|
|
|
// Put cookie to set
|
|
var set = map[cookie.domain]
|
|
if (set == null) {
|
|
set = CookieSet()
|
|
map[cookie.domain] = set
|
|
}
|
|
set.add(cookie)
|
|
} else {
|
|
// Mark to remove the cookie
|
|
toRemove.add(id)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove invalid or expired cookie
|
|
if (toRemove.isNotEmpty()) {
|
|
val statement = db.compileStatement(
|
|
"DELETE FROM $TABLE_COOKIE WHERE $COLUMN_ID = ?;"
|
|
)
|
|
db.beginTransaction()
|
|
try {
|
|
for (id in toRemove) {
|
|
statement.bindLong(1, id)
|
|
statement.executeUpdateDelete()
|
|
}
|
|
db.setTransactionSuccessful()
|
|
} finally {
|
|
db.endTransaction()
|
|
}
|
|
}
|
|
return map
|
|
}
|
|
|
|
private fun toContentValues(cookie: Cookie): ContentValues {
|
|
val contentValues = ContentValues(9)
|
|
contentValues.put(COLUMN_NAME, cookie.name)
|
|
contentValues.put(COLUMN_VALUE, cookie.value)
|
|
contentValues.put(COLUMN_EXPIRES_AT, cookie.expiresAt)
|
|
contentValues.put(COLUMN_DOMAIN, cookie.domain)
|
|
contentValues.put(COLUMN_PATH, cookie.path)
|
|
contentValues.put(COLUMN_SECURE, cookie.secure)
|
|
contentValues.put(COLUMN_HTTP_ONLY, cookie.httpOnly)
|
|
contentValues.put(COLUMN_PERSISTENT, cookie.persistent)
|
|
contentValues.put(COLUMN_HOST_ONLY, cookie.hostOnly)
|
|
return contentValues
|
|
}
|
|
|
|
fun add(cookie: Cookie) {
|
|
val id = db.insert(TABLE_COOKIE, null, toContentValues(cookie))
|
|
if (id != -1L) {
|
|
val oldId = cookieIdMap.put(cookie, id)
|
|
if (oldId != null) Log.e(LOG_TAG, "Add a duplicate cookie")
|
|
} else {
|
|
Log.e(LOG_TAG, "An error occurred when insert a cookie")
|
|
}
|
|
}
|
|
|
|
fun update(from: Cookie, to: Cookie) {
|
|
val id = cookieIdMap[from]
|
|
if (id == null) {
|
|
Log.e(LOG_TAG, "Can't get id when update the cookie")
|
|
return
|
|
}
|
|
val values = toContentValues(to)
|
|
val whereClause = "$COLUMN_ID = ?"
|
|
val whereArgs = arrayOf(id.toString())
|
|
val count = db.update(TABLE_COOKIE, values, whereClause, whereArgs)
|
|
if (count != 1) {
|
|
Log.e(LOG_TAG, "Bad result when update cookie: $count")
|
|
}
|
|
|
|
// Update it in cookie-id map
|
|
cookieIdMap.remove(from)
|
|
cookieIdMap[to] = id
|
|
}
|
|
|
|
fun remove(cookie: Cookie) {
|
|
val id = cookieIdMap[cookie]
|
|
if (id == null) {
|
|
Log.e(LOG_TAG, "Can't get id when remove the cookie")
|
|
return
|
|
}
|
|
val whereClause = "$COLUMN_ID = ?"
|
|
val whereArgs = arrayOf(id.toString())
|
|
val count = db.delete(TABLE_COOKIE, whereClause, whereArgs)
|
|
if (count != 1) {
|
|
Log.e(LOG_TAG, "Bad result when remove cookie: $count")
|
|
}
|
|
|
|
// Remove it from cookie-id map
|
|
cookieIdMap.remove(cookie)
|
|
}
|
|
|
|
fun clear() {
|
|
db.delete(TABLE_COOKIE, null, null)
|
|
cookieIdMap.clear()
|
|
}
|
|
|
|
fun close() {
|
|
db.close()
|
|
helper.close()
|
|
}
|
|
|
|
companion object {
|
|
private val LOG_TAG = CookieDatabase::class.java.simpleName
|
|
private const val VERSION_1 = 1
|
|
private const val TABLE_COOKIE = "OK_HTTP_3_COOKIE"
|
|
private const val COLUMN_ID = "_id"
|
|
private const val COLUMN_NAME = "NAME"
|
|
private const val COLUMN_VALUE = "VALUE"
|
|
private const val COLUMN_EXPIRES_AT = "EXPIRES_AT"
|
|
private const val COLUMN_DOMAIN = "DOMAIN"
|
|
private const val COLUMN_PATH = "PATH"
|
|
private const val COLUMN_SECURE = "SECURE"
|
|
private const val COLUMN_HTTP_ONLY = "HTTP_ONLY"
|
|
private const val COLUMN_PERSISTENT = "PERSISTENT"
|
|
private const val COLUMN_HOST_ONLY = "HOST_ONLY"
|
|
private const val DB_VERSION = VERSION_1
|
|
private fun getCookie(cursor: Cursor, now: Long): Cookie? {
|
|
val name = SqlUtils.getString(cursor, COLUMN_NAME, null)
|
|
val value = SqlUtils.getString(cursor, COLUMN_VALUE, null)
|
|
val expiresAt = SqlUtils.getLong(cursor, COLUMN_EXPIRES_AT, 0)
|
|
val domain = SqlUtils.getString(cursor, COLUMN_DOMAIN, null)
|
|
val path = SqlUtils.getString(cursor, COLUMN_PATH, null)
|
|
val secure = SqlUtils.getBoolean(cursor, COLUMN_SECURE, false)
|
|
val httpOnly = SqlUtils.getBoolean(cursor, COLUMN_HTTP_ONLY, false)
|
|
val persistent = SqlUtils.getBoolean(cursor, COLUMN_PERSISTENT, false)
|
|
val hostOnly = SqlUtils.getBoolean(cursor, COLUMN_HOST_ONLY, false)
|
|
if (name == null || domain == null || path == null) {
|
|
return null
|
|
}
|
|
|
|
// Check non-persistent or expired
|
|
if (!persistent || expiresAt <= now) {
|
|
return null
|
|
}
|
|
val builder = Cookie.Builder()
|
|
builder.name(name)
|
|
builder.value(value)
|
|
if (hostOnly) {
|
|
builder.hostOnlyDomain(domain)
|
|
} else {
|
|
builder.domain(domain)
|
|
}
|
|
builder.path(path)
|
|
builder.expiresAt(expiresAt)
|
|
if (secure) builder.secure()
|
|
if (httpOnly) builder.httpOnly()
|
|
return builder.build()
|
|
}
|
|
}
|
|
|
|
init {
|
|
helper = MSQLiteBuilder()
|
|
.version(VERSION_1)
|
|
.createTable(TABLE_COOKIE)
|
|
.insertColumn(TABLE_COOKIE, COLUMN_NAME, String::class.java)
|
|
.insertColumn(TABLE_COOKIE, COLUMN_VALUE, String::class.java)
|
|
.insertColumn(TABLE_COOKIE, COLUMN_EXPIRES_AT, Long::class.javaPrimitiveType)
|
|
.insertColumn(TABLE_COOKIE, COLUMN_DOMAIN, String::class.java)
|
|
.insertColumn(TABLE_COOKIE, COLUMN_PATH, String::class.java)
|
|
.insertColumn(TABLE_COOKIE, COLUMN_SECURE, Boolean::class.javaPrimitiveType)
|
|
.insertColumn(TABLE_COOKIE, COLUMN_HTTP_ONLY, Boolean::class.javaPrimitiveType)
|
|
.insertColumn(TABLE_COOKIE, COLUMN_PERSISTENT, Boolean::class.javaPrimitiveType)
|
|
.insertColumn(TABLE_COOKIE, COLUMN_HOST_ONLY, Boolean::class.javaPrimitiveType)
|
|
.build(context, name, DB_VERSION)
|
|
db = helper.writableDatabase
|
|
}
|
|
} |