• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright 2018 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package trebuchet.extractors
18 
19 import trebuchet.importers.ImportFeedback
20 import trebuchet.io.*
21 import trebuchet.util.contains
22 import trebuchet.util.searchFor
23 
24 class SystraceExtractor : Extractor {
25     private var startIndex: Long = 0
26     private var endIndex: Long = Long.MAX_VALUE
27 
28     override fun extract(stream: StreamingReader, processSubStream: (BufferProducer) -> Unit) {
29         while (true) {
30             stream.onWindowReleased = null
31             startIndex = START.find(stream, startIndex)
32             if (startIndex == -1L) return
33             startIndex += START.length
34             if (!stream.loadIndex(startIndex)) return
35             if (stream[startIndex] == '\n'.toByte()) startIndex++
36             endIndex = Long.MAX_VALUE
37 
38             val pipe = Pipe<DataSlice>()
39             val thread = Thread {
40                 stream.onWindowReleased = { window -> processWindow(window, pipe) }
41                 endIndex = END.find(stream, startIndex)
42                 if (endIndex == -1L) {
43                     endIndex = stream.endIndex
44                 }
45                 stream.onWindowReleased = null
46                 stream.windows.forEach { processWindow(it, pipe) }
47                 pipe.close()
48             }
49             thread.start()
50 
51             processSubStream(SubStream(pipe))
52 
53             thread.join()
54 
55             startIndex = endIndex
56         }
57     }
58 
59     private class SubStream(val pipe: Pipe<DataSlice>) : BufferProducer {
60         override fun next(): DataSlice? = pipe.next()
61     }
62 
63     private fun processWindow(window: StreamingReader.Window, pipe: Pipe<DataSlice>) {
64         if (window.globalEndIndex >= startIndex && window.globalStartIndex < endIndex) {
65             if (window.globalStartIndex >= startIndex && window.globalEndIndex <= endIndex) {
66                 pipe.add(window.slice)
67             } else {
68                 val sliceStart = maxOf(startIndex - window.globalStartIndex, 0)
69                 val sliceEnd = minOf(endIndex, window.globalEndIndex) - window.globalStartIndex
70                 pipe.add(window.slice.slice(sliceStart.toInt(), sliceEnd.toInt()))
71             }
72         }
73     }
74 
75     private companion object {
76         val START = searchFor("""<script class="trace-data" type="application/text">""")
77         val END = searchFor("""</script>""")
78     }
79 
80     object Factory : ExtractorFactory {
81         override fun extractorFor(buffer: GenericByteBuffer, feedback: ImportFeedback): Extractor? {
82             if (buffer.contains("<html>", 1000)) {
83                 return SystraceExtractor()
84             }
85             return null
86         }
87     }
88 }