summary refs log tree commit diff stats
path: root/tests/importalls/mt7.nim
Commit message (Collapse)AuthorAgeFilesLines
* `import foo {.all.}` reboot (#17706)Timothee Cour2021-04-161-0/+14
ref='#n36'>36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
import net
import streams

import io/multistream
import io/posixstream
import io/serialize
import io/socketstream
import loader/headers

type LoaderHandle* = ref object
  ostream: Stream
  # Stream for taking input
  istream*: PosixStream
  # Only the first handle can be redirected, because a) mailcap can only
  # redirect the first handle and b) async redirects would result in race
  # conditions that would be difficult to untangle.
  canredir: bool
  sostream: Stream # saved ostream when redirected
  sostream_suspend: Stream # saved ostream when suspended
  fd: int

# Create a new loader handle, with the output stream ostream.
proc newLoaderHandle*(ostream: Stream, canredir: bool): LoaderHandle =
  return LoaderHandle(
    ostream: ostream,
    canredir: canredir,
    fd: int(SocketStream(ostream).source.getFd())
  )

proc getFd*(handle: LoaderHandle): int =
  return handle.fd

proc addOutputStream*(handle: LoaderHandle, stream: Stream) =
  if likely(handle.sostream_suspend != nil):
    let ms = newMultiStream(handle.sostream_suspend, stream)
    handle.sostream_suspend = ms
  else:
    # In buffer, addOutputStream is used as follows:
    # * suspend handle
    # * tee handle (-> call addOutputStream)
    # * resume handle
    # This means that this code path will never be executed, as
    # sostream_suspend is never nil when the function is called.
    # (Feel free to remove this assertion if this changes.)
    doAssert false
    let ms = newMultiStream(handle.ostream, stream)
    handle.ostream = ms

proc sendResult*(handle: LoaderHandle, res: int): bool =
  try:
    handle.ostream.swrite(res)
    return true
  except IOError: # broken pipe
    return false

proc sendStatus*(handle: LoaderHandle, status: int): bool =
  try:
    handle.ostream.swrite(status)
    return true
  except IOError: # broken pipe
    return false

proc sendHeaders*(handle: LoaderHandle, headers: Headers): bool =
  try:
    handle.ostream.swrite(headers)
    if handle.canredir:
      var redir: bool
      handle.ostream.sread(redir)
      if redir:
        let fd = SocketStream(handle.ostream).recvFileHandle()
        handle.sostream = handle.ostream
        let stream = newPosixStream(fd)
        handle.ostream = stream
    return true
  except IOError: # broken pipe
    return false

proc sendData*(handle: LoaderHandle, p: pointer, nmemb: int): bool =
  try:
    handle.ostream.writeData(p, nmemb)
    return true
  except IOError: # broken pipe
    return false

proc sendData*(handle: LoaderHandle, s: string): bool =
  if s.len > 0:
    return handle.sendData(unsafeAddr s[0], s.len)
  return true

proc suspend*(handle: LoaderHandle) =
  handle.sostream_suspend = handle.ostream
  handle.ostream = newStringStream()

proc resume*(handle: LoaderHandle) =
  let ss = handle.ostream
  handle.ostream = handle.sostream_suspend
  handle.sostream_suspend = nil
  discard handle.sendData(ss.readAll())
  ss.close()

proc close*(handle: LoaderHandle) =
  if handle.sostream != nil:
    try:
      handle.sostream.swrite(true)
    except IOError:
      # ignore error, that just means the buffer has already closed the stream
      discard
    handle.sostream.close()
  handle.ostream.close()
  if handle.istream != nil:
    handle.istream.close()