about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--doc/config.md2
-rw-r--r--src/buffer/buffer.nim25
-rw-r--r--src/buffer/container.nim7
-rw-r--r--src/css/cssparser.nim7
-rw-r--r--src/display/client.nim2
-rw-r--r--src/io/http.nim5
-rw-r--r--src/io/loader.nim3
-rw-r--r--src/io/posixstream.nim33
-rw-r--r--src/io/urlfilter.nim2
-rw-r--r--src/ips/forkserver.nim7
-rw-r--r--src/ips/serialize.nim6
-rw-r--r--src/ips/socketstream.nim24
-rw-r--r--src/js/regex.nim3
-rw-r--r--src/types/cookie.nim10
14 files changed, 93 insertions, 43 deletions
diff --git a/doc/config.md b/doc/config.md
index 4879621d..a044f719 100644
--- a/doc/config.md
+++ b/doc/config.md
@@ -259,7 +259,7 @@ Examples:
 ```
 # Enable cookies on the orange website for log-in.
 [[siteconf]]
-url = "^https://news.ycombinator.com/.*"
+url = '^https://news\.ycombinator\.com/.*'
 cookie = true
 
 # Redirect npr.org to text.npr.org.
diff --git a/src/buffer/buffer.nim b/src/buffer/buffer.nim
index b692e253..11492834 100644
--- a/src/buffer/buffer.nim
+++ b/src/buffer/buffer.nim
@@ -47,7 +47,8 @@ type
   BufferCommand* = enum
     LOAD, RENDER, WINDOW_CHANGE, FIND_ANCHOR, READ_SUCCESS, READ_CANCELED,
     CLICK, FIND_NEXT_LINK, FIND_PREV_LINK, FIND_NEXT_MATCH, FIND_PREV_MATCH,
-    GET_SOURCE, GET_LINES, UPDATE_HOVER, PASS_FD, CONNECT, GOTO_ANCHOR, CANCEL
+    GET_SOURCE, GET_LINES, UPDATE_HOVER, PASS_FD, CONNECT, GOTO_ANCHOR, CANCEL,
+    GET_TITLE
 
   BufferMatch* = object
     success*: bool
@@ -233,7 +234,7 @@ macro proxy(fun: typed) =
     proxy0(`fun`)
     proxy1(`fun`)
 
-func getTitle(node: StyledNode): string =
+func getTitleAttr(node: StyledNode): string =
   if node == nil:
     return ""
   if node.t == STYLED_ELEMENT and node.node != nil:
@@ -476,7 +477,7 @@ proc updateHover*(buffer: Buffer, cursorx, cursory: int): UpdateHoverResult {.pr
           result.repaint = true
 
     var upd = false
-    let title = thisnode.getTitle()
+    let title = thisnode.getTitleAttr()
     if title != "":
       upd = true
       buffer.hovertext = title
@@ -606,8 +607,9 @@ proc load*(buffer: Buffer): tuple[atend: bool, lines, bytes: int] {.proxy.} =
   try:
     buffer.sstream.setPosition(op + buffer.available)
     let n = buffer.istream.readData(addr s[0], buffer.readbufsize)
+    assert n != 0
     s.setLen(n)
-    result = (n == 0, buffer.lines.len, bytes)
+    result = (false, buffer.lines.len, n)
     buffer.sstream.setPosition(op)
     if buffer.readbufsize < BufferSize:
       buffer.readbufsize = min(BufferSize, buffer.readbufsize * 2)
@@ -617,8 +619,9 @@ proc load*(buffer: Buffer): tuple[atend: bool, lines, bytes: int] {.proxy.} =
       bytes = buffer.available
     else:
       buffer.do_reshape()
-    if result.atend:
-      buffer.finishLoad()
+  except EOFError:
+    result = (true, buffer.lines.len, 0)
+    buffer.finishLoad()
   except ErrorAgain, ErrorWouldBlock:
     buffer.timeout = buffer.lasttimeout
     if buffer.readbufsize == 1:
@@ -630,6 +633,10 @@ proc load*(buffer: Buffer): tuple[atend: bool, lines, bytes: int] {.proxy.} =
       buffer.readbufsize = buffer.readbufsize div 2
     result = (false, buffer.lines.len, bytes)
 
+proc getTitle*(buffer: Buffer): string {.proxy.} =
+  if buffer.document != nil:
+    return buffer.document.title
+
 proc render*(buffer: Buffer): int {.proxy.} =
   buffer.do_reshape()
   return buffer.lines.len
@@ -1081,9 +1088,9 @@ proc runBuffer(buffer: Buffer, rfd: int) =
             try:
               buffer.readCommand()
             except IOError:
-              #eprint "ERROR IN BUFFER", buffer.location
-              #eprint "MESSAGE:", getCurrentExceptionMsg()
-              #eprint getStackTrace(getCurrentException())
+              #eprint "ERROR IN BUFFER", $buffer.location & "\nMESSAGE:",
+              #       getCurrentExceptionMsg() & "\n",
+              #       getStackTrace(getCurrentException())
               break loop
           else:
             assert false
diff --git a/src/buffer/container.nim b/src/buffer/container.nim
index 67c45aa2..5c579c27 100644
--- a/src/buffer/container.nim
+++ b/src/buffer/container.nim
@@ -627,7 +627,12 @@ proc onload(container: Container, res: tuple[atend: bool, lines, bytes: int]) =
       discard container.iface.load().then(proc(res: tuple[atend: bool, lines, bytes: int]) =
         container.onload(res))
     else:
-      container.iface.render().then(proc(lines: int): auto =
+      container.iface.getTitle().then(proc(title: string): auto =
+        if title != "":
+          container.title = title
+          container.triggerEvent(STATUS)
+        return container.iface.render()
+      ).then(proc(lines: int): auto =
         container.setNumLines(lines, true)
         container.needslines = true
         container.triggerEvent(LOADED)
diff --git a/src/css/cssparser.nim b/src/css/cssparser.nim
index 6f26629b..b4a22e28 100644
--- a/src/css/cssparser.nim
+++ b/src/css/cssparser.nim
@@ -163,7 +163,10 @@ func peek(state: CSSTokenizerState, i: int = 0): char =
 
 proc has(state: var CSSTokenizerState, i: int = 0): bool =
   if state.at + i >= state.buf.len and not state.stream.atEnd():
-    state.buf &= state.stream.readLine() & '\n'
+    try:
+      state.buf &= state.stream.readStr(256)
+    except EOFError:
+      return false
   return state.at + i < state.buf.len
 
 proc isValidEscape(a, b: char): bool =
@@ -210,7 +213,7 @@ proc startsWithNumber(state: var CSSTokenizerState): bool =
           if state.has(2) and state.peek(2) in AsciiDigit:
             return true
     of '.':
-      if state.peek(1) in AsciiDigit:
+      if state.has(1) and state.peek(1) in AsciiDigit:
         return true
     elif state.peek() in AsciiDigit:
       return true
diff --git a/src/display/client.nim b/src/display/client.nim
index 9ca2ac68..34077055 100644
--- a/src/display/client.nim
+++ b/src/display/client.nim
@@ -403,7 +403,7 @@ proc launchClient*(client: Client, pages: seq[string], ctype: Option[string], du
   var tty: File
   var dump = dump
   if not dump:
-    if not stdin.isatty():
+    if stdin.isatty():
       tty = stdin
     elif stdout.isatty():
       discard open(tty, "/dev/tty", fmRead)
diff --git a/src/io/http.nim b/src/io/http.nim
index bfd12a0b..36cd6473 100644
--- a/src/io/http.nim
+++ b/src/io/http.nim
@@ -54,12 +54,9 @@ proc curlWriteHeader(p: cstring, size: csize_t, nitems: csize_t, userdata: point
   return nitems
 
 proc curlWriteBody(p: cstring, size: csize_t, nmemb: csize_t, userdata: pointer): csize_t {.cdecl.} =
-  var s = newString(nmemb)
-  for i in 0..<nmemb:
-    s[i] = p[i]
   let stream = cast[Stream](userdata)
   if nmemb > 0:
-    stream.write(s)
+    stream.writeData(p, int(nmemb))
     stream.flush()
   return nmemb
 
diff --git a/src/io/loader.nim b/src/io/loader.nim
index 0b0f5531..3e8baaf0 100644
--- a/src/io/loader.nim
+++ b/src/io/loader.nim
@@ -127,9 +127,8 @@ proc runFileLoader*(fd: cint, defaultHeaders: HeaderList, filter: URLFilter, coo
       of QUIT:
         stream.close()
         break
-    except IOError:
+    except EOFError:
       # End-of-file, quit.
-      # TODO this should be EOFError
       break
     stream.close()
   curl_global_cleanup()
diff --git a/src/io/posixstream.nim b/src/io/posixstream.nim
index 9a40ce9b..b686be9b 100644
--- a/src/io/posixstream.nim
+++ b/src/io/posixstream.nim
@@ -5,6 +5,7 @@ import streams
 type
   PosixStream* = ref object of Stream
     fd*: FileHandle
+    isend*: bool
 
   ErrorAgain* = object of IOError
   ErrorWouldBlock* = object of IOError
@@ -14,17 +15,29 @@ type
   ErrorInvalid* = object of IOError
 
 proc psReadData(s: Stream, buffer: pointer, len: int): int =
+  assert len != 0
   let s = cast[PosixStream](s)
-  result = read(s.fd, buffer, len)
+  while result < len:
+    let n = read(s.fd, buffer, len)
+    if n < 0:
+      if result == 0:
+        result = n
+      break
+    elif n == 0:
+      s.isend = true
+      break
+    result += n
+  if result == 0:
+    raise newException(EOFError, "eof")
   if result == -1:
     if errno == EAGAIN:
-      raise newException(ErrorAgain, "")
+      raise newException(ErrorAgain, "eagain")
     case errno
-    of EWOULDBLOCK: raise newException(ErrorWouldBlock, "")
-    of EBADF: raise newException(ErrorBadFD, "")
-    of EFAULT: raise newException(ErrorFault, "")
-    of EINVAL: raise newException(ErrorInvalid, "")
-    else: raise newException(IOError, $strerror(errno))
+    of EWOULDBLOCK: raise newException(ErrorWouldBlock, "would block")
+    of EBADF: raise newException(ErrorBadFD, "bad fd")
+    of EFAULT: raise newException(ErrorFault, "fault")
+    of EINVAL: raise newException(ErrorInvalid, "invalid")
+    else: raise newException(IOError, $strerror(errno) & " (" & $errno & ")")
 
 proc psWriteData(s: Stream, buffer: pointer, len: int) =
   let s = cast[PosixStream](s)
@@ -32,9 +45,13 @@ proc psWriteData(s: Stream, buffer: pointer, len: int) =
   if res == -1:
     raise newException(IOError, $strerror(errno))
 
+proc psAtEnd(s: Stream): bool =
+  return cast[PosixStream](s).isend
+
 proc newPosixStream*(fd: FileHandle): PosixStream =
   return PosixStream(
     fd: fd,
     readDataImpl: psReadData,
-    writeDataImpl: psWriteData
+    writeDataImpl: psWriteData,
+    atEndImpl: psAtEnd
   )
diff --git a/src/io/urlfilter.nim b/src/io/urlfilter.nim
index 29dad8c6..28bdef28 100644
--- a/src/io/urlfilter.nim
+++ b/src/io/urlfilter.nim
@@ -6,7 +6,7 @@ import types/url
 #TODO add denyhost/s for blocklists
 type URLFilter* = object
   scheme: Option[string]
-  allowhost: Option[string]
+  allowhost*: Option[string]
   allowhosts: Option[seq[Regex]]
   default: bool
 
diff --git a/src/ips/forkserver.nim b/src/ips/forkserver.nim
index e8904354..29463248 100644
--- a/src/ips/forkserver.nim
+++ b/src/ips/forkserver.nim
@@ -6,6 +6,7 @@ when defined(posix):
 import buffer/buffer
 import config/config
 import io/loader
+import io/posixstream
 import io/request
 import io/urlfilter
 import io/window
@@ -92,8 +93,8 @@ proc forkBuffer(ctx: var ForkServerContext): Pid =
 
 proc runForkServer() =
   var ctx: ForkServerContext
-  ctx.istream = newFileStream(stdin)
-  ctx.ostream = newFileStream(stdout)
+  ctx.istream = newPosixStream(stdin.getFileHandle())
+  ctx.ostream = newPosixStream(stdout.getFileHandle())
   while true:
     try:
       var cmd: ForkCommand
@@ -124,7 +125,7 @@ proc runForkServer() =
         width_table = makewidthtable(config.ambiguous_double)
         SocketDirectory = config.tmpdir
       ctx.ostream.flush()
-    except IOError:
+    except EOFError:
       # EOF
       break
   ctx.istream.close()
diff --git a/src/ips/serialize.nim b/src/ips/serialize.nim
index ed35371a..05f05ac9 100644
--- a/src/ips/serialize.nim
+++ b/src/ips/serialize.nim
@@ -116,7 +116,11 @@ proc swrite*(stream: Stream, s: string) =
 proc sread*(stream: Stream, s: var string) =
   var len: int
   stream.sread(len)
-  stream.readStr(len, s)
+  if len > 0:
+    stream.readStr(len, s)
+  else:
+    s = ""
+
 func slen*(s: string): int =
   slen(s.len) + s.len
 
diff --git a/src/ips/socketstream.nim b/src/ips/socketstream.nim
index 4f98517c..6d3e5cd9 100644
--- a/src/ips/socketstream.nim
+++ b/src/ips/socketstream.nim
@@ -15,26 +15,32 @@ type SocketStream* = ref object of Stream
   isend: bool
 
 proc sockReadData(s: Stream, buffer: pointer, len: int): int =
+  assert len != 0
   let s = SocketStream(s)
   if s.blk:
     while result < len:
       let n = s.source.recv(cast[pointer](cast[int](buffer) + result), len - result)
-      result += n
-      if n == 0:
-        raise newException(EOFError, "")
       if n < 0:
-        result = n
+        if result == 0:
+          result = n
+        break
+      elif n == 0:
+        s.isend = true
         break
+      result += n
   else:
     result = s.source.recv(buffer, len)
+  if result == 0:
+    s.isend = true
+    raise newException(EOFError, "eof")
   if result < 0:
     if errno == EAGAIN:
-      raise newException(ErrorAgain, "")
+      raise newException(ErrorAgain, "eagain")
     case errno
-    of EWOULDBLOCK: raise newException(ErrorWouldBlock, "")
-    of EBADF: raise newException(ErrorBadFD, "")
-    of EFAULT: raise newException(ErrorFault, "")
-    of EINVAL: raise newException(ErrorInvalid, "")
+    of EWOULDBLOCK: raise newException(ErrorWouldBlock, "would block")
+    of EBADF: raise newException(ErrorBadFD, "bad fd")
+    of EFAULT: raise newException(ErrorFault, "fault")
+    of EINVAL: raise newException(ErrorInvalid, "invalid")
     else: raise newException(IOError, $strerror(errno))
   elif result == 0:
     s.isend = true
diff --git a/src/js/regex.nim b/src/js/regex.nim
index a4652373..391cb46b 100644
--- a/src/js/regex.nim
+++ b/src/js/regex.nim
@@ -109,6 +109,9 @@ proc `=copy`(dest: var Regex, source: Regex) =
     dest.buf = source.buf
     dest.plen = source.plen
 
+func `$`*(regex: Regex): string =
+  regex.buf
+
 proc compileRegex*(buf: string, flags: int): Option[Regex] =
   var regex: Regex
   var error_msg_size = 64
diff --git a/src/types/cookie.nim b/src/types/cookie.nim
index c848813d..e5e50d3e 100644
--- a/src/types/cookie.nim
+++ b/src/types/cookie.nim
@@ -21,7 +21,7 @@ type
     path {.jsget.}: string
 
   CookieJar* = ref object
-    filter: URLFilter
+    filter*: URLFilter
     cookies*: seq[Cookie]
 
 proc parseCookieDate(val: string): Option[DateTime] =
@@ -109,6 +109,14 @@ proc parseCookieDate(val: string): Option[DateTime] =
   var dateTime = dateTime(year, Month(month), MonthdayRange(dayOfMonth), HourRange(time[0]), MinuteRange(time[1]), SecondRange(time[2]))
   return some(dateTime)
 
+# For debugging
+proc `$`*(cookiejar: CookieJar): string =
+  result &= $cookiejar.filter
+  result &= "\n"
+  for cookie in cookiejar.cookies:
+    result &= "Cookie "
+    result &= $cookie[]
+
 proc serialize*(cookiejar: CookieJar, location: URL): string =
   if not cookiejar.filter.match(location):
     return "" # fail