1919 */
2020package net.ccbluex.netty.http.rest
2121
22+ import io.netty.buffer.ByteBuf
23+ import io.netty.buffer.Unpooled
24+ import io.netty.handler.codec.http.DefaultFullHttpResponse
25+ import io.netty.handler.codec.http.EmptyHttpHeaders
2226import io.netty.handler.codec.http.FullHttpResponse
23- import net.ccbluex.netty.http.util.httpFileStream
27+ import io.netty.handler.codec.http.HttpHeaderNames
28+ import io.netty.handler.codec.http.HttpResponseStatus
29+ import io.netty.handler.codec.http.HttpVersion
30+ import io.netty.handler.codec.http.ReadOnlyHttpHeaders
2431import net.ccbluex.netty.http.util.httpNotFound
2532import net.ccbluex.netty.http.model.RequestObject
2633import org.apache.tika.Tika
27- import java.io.ByteArrayInputStream
2834import java.io.InputStream
2935import java.util.zip.ZipEntry
3036import java.util.zip.ZipInputStream
3137
38+ private val tika = Tika ()
39+
3240/* *
3341 * Represents a zip servant in the routing tree that serves files from a zip archive kept in memory.
3442 *
@@ -48,32 +56,28 @@ class ZipServant(part: String, zipInputStream: InputStream) : Node(part) {
4856 */
4957 private data class ZipFileEntry (
5058 val name : String ,
51- val data : ByteArray ,
52- val isDirectory : Boolean
59+ val data : ByteBuf ,
60+ val isDirectory : Boolean ,
5361 ) {
54- override fun equals (other : Any? ): Boolean {
55- if (this == = other) return true
56- if (javaClass != other?.javaClass) return false
57-
58- other as ZipFileEntry
59-
60- if (name != other.name) return false
61- if (! data.contentEquals(other.data)) return false
62- if (isDirectory != other.isDirectory) return false
63-
64- return true
65- }
62+ private val headers =
63+ ReadOnlyHttpHeaders (
64+ false ,
65+ HttpHeaderNames .CONTENT_TYPE , tika.detect(name),
66+ HttpHeaderNames .CONTENT_LENGTH , data.readableBytes().toString(),
67+ )
6668
67- override fun hashCode (): Int {
68- var result = name.hashCode()
69- result = 31 * result + data.contentHashCode()
70- result = 31 * result + isDirectory.hashCode()
71- return result
69+ fun toResponse (): FullHttpResponse {
70+ return DefaultFullHttpResponse (
71+ HttpVersion .HTTP_1_1 ,
72+ HttpResponseStatus .OK ,
73+ data.duplicate(),
74+ headers,
75+ EmptyHttpHeaders .INSTANCE ,
76+ )
7277 }
7378 }
7479
7580 private val zipFiles: Map <String , ZipFileEntry >
76- private val tika = Tika ()
7781
7882 init {
7983 zipFiles = loadZipData(zipInputStream)
@@ -96,10 +100,10 @@ class ZipServant(part: String, zipInputStream: InputStream) : Node(part) {
96100 val isDirectory = entry.isDirectory
97101
98102 if (isDirectory) {
99- files[name] = ZipFileEntry (name, ByteArray ( 0 ) , true )
103+ files[name] = ZipFileEntry (name, Unpooled . EMPTY_BUFFER , true )
100104 } else {
101105 val data = zis.readBytes()
102- files[name] = ZipFileEntry (name, data, false )
106+ files[name] = ZipFileEntry (name, Unpooled .wrappedBuffer( data) , false )
103107 }
104108
105109 zis.closeEntry()
@@ -110,8 +114,8 @@ class ZipServant(part: String, zipInputStream: InputStream) : Node(part) {
110114 return files
111115 }
112116
113- override fun handleRequest ( requestObject : RequestObject ): FullHttpResponse {
114- val path = requestObject .remainingPath.removePrefix(" /" )
117+ override fun handle ( request : RequestObject ): FullHttpResponse {
118+ val path = request .remainingPath.removePrefix(" /" )
115119 val cleanPath = path.substringBefore(" ?" )
116120 val sanitizedPath = cleanPath.replace(" .." , " " )
117121
@@ -141,11 +145,7 @@ class ZipServant(part: String, zipInputStream: InputStream) : Node(part) {
141145 // Try to find exact file match first (non-directory)
142146 val exactMatch = findFile(sanitizedPath)
143147 if (exactMatch != null && ! exactMatch.isDirectory) {
144- return httpFileStream(
145- stream = ByteArrayInputStream (exactMatch.data),
146- contentType = tika.detect(exactMatch.name),
147- contentLength = exactMatch.data.size
148- )
148+ return exactMatch.toResponse()
149149 }
150150
151151 // Handle directory requests or SPA routes
@@ -154,47 +154,31 @@ class ZipServant(part: String, zipInputStream: InputStream) : Node(part) {
154154 sanitizedPath.isEmpty() -> {
155155 val indexEntry = findIndexInDirectory(" " )
156156 if (indexEntry != null && ! indexEntry.isDirectory) {
157- return httpFileStream(
158- stream = ByteArrayInputStream (indexEntry.data),
159- contentType = tika.detect(indexEntry.name),
160- contentLength = indexEntry.data.size
161- )
157+ return indexEntry.toResponse()
162158 }
163159 }
164160
165161 // Case 2: Path ends with "/" - explicit directory request
166162 sanitizedPath.endsWith(" /" ) -> {
167163 val indexEntry = findIndexInDirectory(directoryPath)
168164 if (indexEntry != null && ! indexEntry.isDirectory) {
169- return httpFileStream(
170- stream = ByteArrayInputStream (indexEntry.data),
171- contentType = tika.detect(indexEntry.name),
172- contentLength = indexEntry.data.size
173- )
165+ return indexEntry.toResponse()
174166 }
175167 }
176168
177169 // Case 3: Path contains "#" - SPA route with fragment
178170 fragmentIndex != - 1 -> {
179171 val indexEntry = findIndexInDirectory(directoryPath)
180172 if (indexEntry != null && ! indexEntry.isDirectory) {
181- return httpFileStream(
182- stream = ByteArrayInputStream (indexEntry.data),
183- contentType = tika.detect(indexEntry.name),
184- contentLength = indexEntry.data.size
185- )
173+ return indexEntry.toResponse()
186174 }
187175 }
188176
189177 // Case 4: Check if path is an implicit directory and has index.html
190178 isImplicitDirectory(sanitizedPath) -> {
191179 val indexEntry = findIndexInDirectory(sanitizedPath)
192180 if (indexEntry != null && ! indexEntry.isDirectory) {
193- return httpFileStream(
194- stream = ByteArrayInputStream (indexEntry.data),
195- contentType = tika.detect(indexEntry.name),
196- contentLength = indexEntry.data.size
197- )
181+ return indexEntry.toResponse()
198182 }
199183 }
200184 }
0 commit comments