Skip to content

Commit 2a3aad4

Browse files
committed
add support for chunked transfer encoding
1 parent b3a68cf commit 2a3aad4

File tree

4 files changed

+51
-11
lines changed

4 files changed

+51
-11
lines changed

src/main/kotlin/dev/samicpp/http/Generics.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ interface HttpClient{
2121
val path: String;
2222
val host: String;
2323
val body: ByteArray;
24+
25+
val isReady: Boolean; // indicates whether headers can be used
26+
val isComplete: Boolean;
2427
}
2528

2629
interface HttpSocket{

src/main/kotlin/dev/samicpp/http/Testing.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class FakeHttpClient: HttpClient{
1515
override val path: String = "/"
1616
override val host: String = "about:blank"
1717
override val body: ByteArray = ByteArray(0)
18+
override val isReady: Boolean = true
19+
override val isComplete: Boolean = true
1820
}
1921

2022
class FakeHttpSocket: HttpSocket{

src/main/kotlin/dev/samicpp/http/http1/Http1Socket.kt

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -226,14 +226,16 @@ class Http1Socket(private val conn:Socket):HttpSocket{
226226

227227
override fun readClient():HttpClient{
228228
if(!read_head){
229-
val head=read_until("\r\n\r\n".encodeToByteArray()).decodeToString().replace("\r\n","\n").split("\n")
229+
val head=read_until("\r\n\r\n".encodeToByteArray()).decodeToString()/*.replace("\r\n","\n")*/.split("\r\n")
230230
val (method,path,version)=head[0].split(" ")
231231
_client._method=method
232232
_client._path=path
233233
_client._version=version
234234

235235
for(i in 1 until head.size){
236-
val (headerb,value)=head[i].split(":",limit=2)
236+
val col=head[i].split(":",limit=2)
237+
if(col.size<2)continue
238+
val (headerb,value)=col
237239
val header=headerb.lowercase()
238240
if(header in _client._headers){
239241
_client._headers[header]!!.add(value.trim())
@@ -242,11 +244,28 @@ class Http1Socket(private val conn:Socket):HttpSocket{
242244
}
243245
}
244246
read_head=true
247+
_client._ready=true
245248
}; if(!read_body) {
246-
// TODO: support chunked transfer encoding
247-
val cl=_client._headers["content-length"]?.get(0)?.toInt()?:0
248-
_client._body=read_certain(cl)
249-
read_body=true
249+
if(_client._headers["content-length"]?.get(0)!=null){
250+
251+
val cl=_client._headers["content-length"]!!.get(0).toInt()
252+
_client._body.writeBytes(read_certain(cl))
253+
read_body=true
254+
_client._bodyComplete=true
255+
256+
} else if(_client._headers["transfer-encoding"]?.get(0)=="chunked"){
257+
258+
val chunk=read_until("\r\n".encodeToByteArray()).decodeToString().trim().toInt(16)
259+
if(chunk==0){
260+
_client._bodyComplete=true
261+
read_body=true
262+
}
263+
else _client._body.write(read_certain(chunk+2),0,chunk)
264+
265+
} else {
266+
_client._bodyComplete=true
267+
read_body=true
268+
}
250269
}
251270

252271
// val buff=read_all()
@@ -336,14 +355,18 @@ class Http1Client(override val address:SocketAddress):HttpClient{
336355
internal var _method=""
337356
internal var _version=""
338357
internal var _path=""
339-
internal var _body=ByteArray(0)
358+
internal var _body=ByteArrayOutputStream()
359+
internal var _ready=false
360+
internal var _bodyComplete=false
340361

341362
override val headers: Map<String,List<String>> get()=_headers
342363
override val method: String get()=_method
343364
override val version: String get()=_version
344365
override val path: String get()=_path
345366
override val host: String get()=_headers["host"]?.get(0)?:"about:blank"
346-
override val body: ByteArray get()=_body
367+
override val body: ByteArray get()=_body.toByteArray()
368+
override val isReady get()=_ready
369+
override val isComplete get()=_bodyComplete
347370
}
348371

349372
// fun ByteArray.indexOfSequence(sequence:ByteArray):Int{

src/main/kotlin/dev/samicpp/http/http2/Http2Streams.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@ import dev.samicpp.http.Http2Client
44
import java.net.SocketAddress
55

66

7-
data class Http2Client(val head:List<Pair<String,String>>,override val body:ByteArray,override val address:SocketAddress):HttpClient{
7+
data class Http2Client(
8+
val head:List<Pair<String,String>>,
9+
override val body:ByteArray,
10+
override val address:SocketAddress,
11+
override val isComplete: Boolean,
12+
):HttpClient{
813
override val headers: Map<String,List<String>>
914
override val method: String
1015
override val version: String="HTTP/2"
1116
override val path: String
1217
override val host: String
18+
override val isReady: Boolean
1319
init{
1420
val headers=mutableMapOf<String,MutableList<String>>()
1521
var method="GET"
@@ -32,13 +38,14 @@ data class Http2Client(val head:List<Pair<String,String>>,override val body:Byte
3238
this.host=host
3339
this.method=method
3440
this.headers=headers
41+
this.isReady=head.size>0
3542
}
3643
}
3744

3845
// TODO: make sure headers dont exceed SETTINGS_MAX_HEADER_LIST_SIZE
3946

4047
class Http2Stream(val streamID:Int,val conn:Http2Connection):HttpSocket{
41-
override var client: HttpClient=Http2Client(listOf(),ByteArray(0),conn.remoteAddress)
48+
override var client: HttpClient=Http2Client(listOf(),ByteArray(0),conn.remoteAddress,false)
4249

4350
private var sentHead=false
4451
private var closed=false
@@ -135,7 +142,12 @@ class Http2Stream(val streamID:Int,val conn:Http2Connection):HttpSocket{
135142
override fun write(text:String)=write(text.encodeToByteArray())
136143

137144
override fun readClient():HttpClient{
138-
val nclient=Http2Client(conn.streamData[streamID]!!.headers,conn.streamData[streamID]!!.body.toByteArray(),conn.remoteAddress)
145+
val nclient=Http2Client(
146+
conn.streamData[streamID]!!.headers,
147+
conn.streamData[streamID]!!.body.toByteArray(),
148+
conn.remoteAddress,
149+
conn.streamData[streamID]!!.end,
150+
)
139151
client=nclient
140152
return client
141153
}

0 commit comments

Comments
 (0)