From b85bbdbc314f1a5a7b7b80aa38633bc6ddf38473 Mon Sep 17 00:00:00 2001 From: spamegg1 Date: Thu, 4 Jul 2024 16:21:01 +0300 Subject: [PATCH] update deps, ch06 finally figured out http parse bug! --- project.scala | 6 +- src/main/scala/ch06/asyncHttp/http.scala | 43 ++++++----- src/main/scala/ch06/asyncHttp/main.scala | 91 +++++++++++++++++++++++- src/main/scala/ch06/common/libuv.scala | 2 +- 4 files changed, 117 insertions(+), 25 deletions(-) diff --git a/project.scala b/project.scala index 70eabfc..d2217c5 100644 --- a/project.scala +++ b/project.scala @@ -1,8 +1,8 @@ //> using scala 3.4.2 //> using platform native -//> using nativeVersion 0.5.2 +//> using nativeVersion 0.5.4 //> using exclude "gatling/*" //> using options -explain-cyclic -Ydebug-cyclic -//> using dep io.argonaut::argonaut:6.3.9 -//> using dep io.gatling:gatling-app:3.11.3 +//> using dep io.argonaut::argonaut:6.3.10 +//> using dep io.gatling:gatling-app:3.11.5 // // > using dep biz.enef:slogging_2.13:0.6.2 diff --git a/src/main/scala/ch06/asyncHttp/http.scala b/src/main/scala/ch06/asyncHttp/http.scala index 60ba93f..0b69385 100644 --- a/src/main/scala/ch06/asyncHttp/http.scala +++ b/src/main/scala/ch06/asyncHttp/http.scala @@ -10,6 +10,7 @@ import scalanative.libc.string.{strlen, strncpy} object HTTP: import ch03.httpClient.{HttpRequest, HttpResponse} + import scala.util.boundary, boundary.break case class HeaderLine( key: CString, @@ -51,7 +52,6 @@ object HTTP: valueEnd: Ptr[Int], lineLen: Ptr[Int] ): Int = - !lineLen = -1 val scanResult = stdio.sscanf( line, c"%*[^\r\n:]%n: %n%*[^\r\n]%n%*[\r\n]%n", // Content-Type: text/html; charset=UTF-8 @@ -74,7 +74,7 @@ object HTTP: outMap(key) = value // add to Scala map !lineLen - else throw Exception("bad header line") // WE GET THIS! + else throw Exception("bad header line") val lineBuffer = malloc(1024) // 0.5 @@ -90,23 +90,28 @@ object HTTP: val (method, uri, requestLen) = scanRequestLine(req) var bytesRead = requestLen - while bytesRead < size do - reqPosition = req + bytesRead - val parseHeaderResult = - scanHeaderLine(reqPosition, headers, keyEnd, valueStart, valueEnd, lineLen) - if parseHeaderResult < 0 then throw Exception("HEADERS INCOMPLETE") - - // if there are 2 bytes left, there is another header. - else if !lineLen - !valueEnd == 2 then bytesRead += parseHeaderResult - - // if there are 4 bytes left, this was the last header, now comes the body. - else if !lineLen - !valueEnd == 4 then - val remaining = size - bytesRead - val body = fromCString(req + bytesRead) // yep, the rest is the body. - HttpRequest(method, uri, headers, body) // return this value and finish. - else throw Exception("malformed header!") - - throw Exception(s"bad scan, exceeded $size bytes") // we shouldn't reach here! + boundary: + while bytesRead < size do + println(s"bytesRead: $bytesRead") + reqPosition = req + bytesRead + val parseHeaderResult = + scanHeaderLine(reqPosition, headers, keyEnd, valueStart, valueEnd, lineLen) + if parseHeaderResult < 0 then throw Exception("HEADERS INCOMPLETE") + + // if there are 2 bytes left, there is another header. + else if !lineLen - !valueEnd == 2 then + println("2 bytes left") + bytesRead += parseHeaderResult + + // if there are 4 bytes left, this was the last header, now comes the body. + else if !lineLen - !valueEnd == 4 then + println("4 bytes left") + val remaining = size - bytesRead + val body = fromCString(req + bytesRead) // yep, the rest is the body. + break(HttpRequest(method, uri, headers, body)) // return this value and finish. + else throw Exception("malformed header!") + + throw Exception(s"bad scan, exceeded $size bytes") // we shouldn't reach here! val keyBuffer = malloc(512) // 0.5 val valueBuffer = malloc(512) // 0.5 diff --git a/src/main/scala/ch06/asyncHttp/main.scala b/src/main/scala/ch06/asyncHttp/main.scala index ab77eb3..ad016b9 100644 --- a/src/main/scala/ch06/asyncHttp/main.scala +++ b/src/main/scala/ch06/asyncHttp/main.scala @@ -10,8 +10,7 @@ import LibUV.*, LibUVConstants.* import HTTP.RequestHandler import ch03.httpClient.{HttpRequest, HttpResponse} -// when run, and connecting on browser http://localhost:8080 -// I am always getting "error bad header line" from scanHeaderLine function! +// when run, connect on browser http://localhost:8080 to see hello world. @main def run: Unit = serveHttp(8080, router) @@ -66,3 +65,91 @@ def sendResponse(client: TCPHandle, response: HttpResponse): Unit = responseBuffer._2 = string.strlen(responseBuffer._1) !req = responseBuffer.asInstanceOf[Ptr[Byte]] checkError(uv_write(req, client, responseBuffer, 1, writeCB), "uv_write") + +// about to serve on port 8080 +// uv_ip4_addr returned 0 +// uv_tcp_init(server) returned 0 +// uv_tcp_bind returned 0 +// uv_tcp_listen returned 0 +// received connection +// uv_tcp_init(client) returned 0 +// allocated data at 5eaa0420; assigning into handle storage at 5eaa0320 +// uv_accept returned 0 +// uv_read_start returned 0 +// allocating 4096 bytes +// bytesRead: 16 +// 2 bytes left +// bytesRead: 38 +// 2 bytes left +// bytesRead: 122 +// 2 bytes left +// bytesRead: 217 +// 2 bytes left +// bytesRead: 250 +// 2 bytes left +// bytesRead: 292 +// 2 bytes left +// bytesRead: 300 +// 2 bytes left +// bytesRead: 312 +// 2 bytes left +// bytesRead: 336 +// 2 bytes left +// bytesRead: 366 +// 2 bytes left +// bytesRead: 392 +// 2 bytes left +// bytesRead: 418 +// 2 bytes left +// bytesRead: 440 +// 2 bytes left +// bytesRead: 460 +// 4 bytes left +// uv_write returned 0 +// uv_shutdown returned 0 +// write completed +// all pending writes complete, closing TCP connection +// uv_close returned 1551708544: +// Unknown system error 1551708544: Unknown system error 1551708544 +// closed client connection +// received connection +// uv_tcp_init(client) returned 0 +// allocated data at 5eaa0420; assigning into handle storage at 5eaa0320 +// uv_accept returned 0 +// uv_read_start returned 0 +// allocating 4096 bytes +// bytesRead: 27 +// 2 bytes left +// bytesRead: 49 +// 2 bytes left +// bytesRead: 133 +// 2 bytes left +// bytesRead: 168 +// 2 bytes left +// bytesRead: 201 +// 2 bytes left +// bytesRead: 243 +// 2 bytes left +// bytesRead: 251 +// 2 bytes left +// bytesRead: 263 +// 2 bytes left +// bytesRead: 287 +// 2 bytes left +// bytesRead: 320 +// 2 bytes left +// bytesRead: 343 +// 2 bytes left +// bytesRead: 368 +// 2 bytes left +// bytesRead: 397 +// 4 bytes left +// uv_write returned 0 +// uv_shutdown returned 0 +// write completed +// all pending writes complete, closing TCP connection +// uv_close returned 1551708544: +// Unknown system error 1551708544: Unknown system error 1551708544 +// closed client connection +// Then I see hello world on browser! +// YAY! diff --git a/src/main/scala/ch06/common/libuv.scala b/src/main/scala/ch06/common/libuv.scala index e186103..18828db 100644 --- a/src/main/scala/ch06/common/libuv.scala +++ b/src/main/scala/ch06/common/libuv.scala @@ -11,7 +11,7 @@ object LibUV: // If we do, there are many compiler errors to be fixed with .asInstanceOf[...]. type TimerHandle = Ptr[Byte] // book says Ptr[Ptr[Byte]], what should it be? type PipeHandle = Ptr[Ptr[Byte]] - type Loop = Ptr[Byte] // book says Ptr[Ptr[Byte]], what should it be? + type Loop = Ptr[Ptr[Byte]] // book says Ptr[Ptr[Byte]], what should it be? type TCPHandle = Ptr[Ptr[Byte]] // code treats it as Ptr[Byte], what should it be? type WriteReq = Ptr[Ptr[Byte]] type ShutdownReq = Ptr[Ptr[Byte]] // should it be Ptr[TCPHandle]?