Search code examples
httpserverclientnim-lang

Nimlang: Async program does not compile


I'm trying to write a HTTP server that sends a HTTP request and returns the content to client.

Here is the code:

import asynchttpserver, asyncdispatch
import httpClient

let client = newHttpClient()

var server = newAsyncHttpServer()

proc cb(req: Request) {.async.} =

  let content = client.getContent("http://google.com")
  await req.respond(Http200, content)

waitFor server.serve(Port(8080), cb)

However, I obtain the following compile error message (nim v1.0.0):

Error: type mismatch: got <AsyncHttpServer, Port, proc (req: Request): Future[system.void]{.locks: <unknown>.}>
but expected one of:
proc serve(server: AsyncHttpServer; port: Port;
          callback: proc (request: Request): Future[void] {.closure, gcsafe.};
          address = ""): owned(Future[void])
  first type mismatch at position: 3
  required type for callback: proc (request: Request): Future[system.void]{.closure, gcsafe.}
  but expression 'cb' is of type: proc (req: Request): Future[system.void]{.locks: <unknown>.}
  This expression is not GC-safe. Annotate the proc with {.gcsafe.} to get extended error information.

expression: serve(server, Port(8080), cb)

The serve function expects another expression but do not know how to fix it. Surprisingly, the code compiles perfectly fine when I remove the HTTP request from the server callback "cb". Does this mean that the serve function expects different callback expressions depending on the callback body ?


Solution

  • OK the problem is that the HttpClient is a global variable and is used in the callback function "cb". As a result the callback function is not GC safe.

    So it is enough to instantiate the HttpClient within the callback function:

    import asynchttpserver, asyncdispatch
    import httpClient
    
    
    
    var server = newAsyncHttpServer()
    
    proc cb(req: Request) {.async.} =
    
      let client = newHttpClient()
    
      let content = client.getContent("https://google.com")
    
      await req.respond(Http200, content)
    
    waitFor server.serve(Port(8080), cb)