1package com.catviewer
2
3import java.io.{IOException, InputStream}
4import java.net.URLConnection
5import org.cef.callback.CefCallback
6import org.cef.handler.{CefLoadHandler, CefResourceHandler}
7import org.cef.misc.{IntRef, StringRef}
8import org.cef.network.{CefRequest, CefResponse}
9
10class CustomResourceHandler extends CefResourceHandler {
11 private var state: ResourceHandlerState = ClosedConnection
12 override def processRequest(
13 cefRequest: CefRequest,
14 cefCallback: CefCallback
15 ): Boolean = {
16 val urlOption = Option(cefRequest.getURL)
17 urlOption match {
18 case Some(processedUrl) =>
19 val pathToResource = processedUrl.replace("http://myapp", "webview/")
20 val newUrl = getClass.getClassLoader.getResource(pathToResource)
21 state = OpenedConnection(
22 newUrl.openConnection()
23 )
24 cefCallback.Continue()
25 true
26 case None => false
27 }
28 }
29
30 override def getResponseHeaders(
31 cefResponse: CefResponse,
32 responseLength: IntRef,
33 redirectUrl: StringRef
34 ): Unit = {
35 state.getResponseHeaders(cefResponse, responseLength, redirectUrl)
36 }
37
38 override def readResponse(
39 dataOut: Array[Byte],
40 designedBytesToRead: Int,
41 bytesRead: IntRef,
42 callback: CefCallback
43 ): Boolean = {
44 state.readResponse(dataOut, designedBytesToRead, bytesRead, callback)
45 }
46
47 override def cancel(): Unit = {
48 state.close()
49 state = ClosedConnection
50 }
51}
52
53sealed trait ResourceHandlerState {
54 def getResponseHeaders(
55 cefResponse: CefResponse,
56 responseLength: IntRef,
57 redirectUrl: StringRef
58 ): Unit
59
60 def readResponse(
61 dataOut: Array[Byte],
62 designedBytesToRead: Int,
63 bytesRead: IntRef,
64 callback: CefCallback
65 ): Boolean
66
67 def close(): Unit = {}
68}
69
70case class OpenedConnection(connection: URLConnection)
71 extends ResourceHandlerState {
72 private lazy val inputStream: InputStream = connection.getInputStream
73 override def getResponseHeaders(
74 cefResponse: CefResponse,
75 responseLength: IntRef,
76 redirectUrl: StringRef
77 ): Unit = {
78 try {
79 val url = connection.getURL.toString
80 url match {
81 case x if x.contains("css") => cefResponse.setMimeType("text/css")
82 case x if x.contains("js") =>
83 cefResponse.setMimeType("text/javascript")
84 case x if x.contains("html") => cefResponse.setMimeType("text/html")
85 case _ => cefResponse.setMimeType(connection.getContentType)
86 }
87 responseLength.set(inputStream.available())
88 cefResponse.setStatus(200)
89 } catch {
90 case e: IOException =>
91 cefResponse.setError(CefLoadHandler.ErrorCode.ERR_FILE_NOT_FOUND)
92 cefResponse.setStatusText(e.getLocalizedMessage)
93 cefResponse.setStatus(404)
94 }
95 }
96
97 override def readResponse(
98 dataOut: Array[Byte],
99 designedBytesToRead: Int,
100 bytesRead: IntRef,
101 callback: CefCallback
102 ): Boolean = {
103 val availableSize = inputStream.available()
104 if (availableSize > 0) {
105 val maxBytesToRead = Math.min(availableSize, designedBytesToRead)
106 val realNumberOfReadBytes =
107 inputStream.read(dataOut, 0, maxBytesToRead)
108 bytesRead.set(realNumberOfReadBytes)
109 true
110 } else {
111 inputStream.close()
112 false
113 }
114 }
115
116 override def close(): Unit = {
117 inputStream.close()
118 }
119}
120
121case object ClosedConnection extends ResourceHandlerState {
122 override def getResponseHeaders(
123 cefResponse: CefResponse,
124 responseLength: IntRef,
125 redirectUrl: StringRef
126 ): Unit = {
127 cefResponse.setStatus(404)
128 }
129
130 override def readResponse(
131 dataOut: Array[Byte],
132 designedBytesToRead: Int,
133 bytesRead: IntRef,
134 callback: CefCallback
135 ): Boolean = {
136 false
137 }
138}