Skip to content

Commit

Permalink
update deps, ch06 finally figured out http parse bug!
Browse files Browse the repository at this point in the history
  • Loading branch information
spamegg1 committed Jul 4, 2024
1 parent aa558f5 commit b85bbdb
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 25 deletions.
6 changes: 3 additions & 3 deletions project.scala
Original file line number Diff line number Diff line change
@@ -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
43 changes: 24 additions & 19 deletions src/main/scala/ch06/asyncHttp/http.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand All @@ -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
Expand Down
91 changes: 89 additions & 2 deletions src/main/scala/ch06/asyncHttp/main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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!
2 changes: 1 addition & 1 deletion src/main/scala/ch06/common/libuv.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]?
Expand Down

0 comments on commit b85bbdb

Please sign in to comment.