diff options
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | adapter/img/canvas.nim | 3 | ||||
-rw-r--r-- | src/html/dom.nim | 45 | ||||
-rw-r--r-- | src/img/painter.nim | 32 | ||||
-rw-r--r-- | src/img/path.nim | 26 | ||||
-rw-r--r-- | src/io/bufreader.nim | 78 | ||||
-rw-r--r-- | src/io/bufwriter.nim | 59 | ||||
-rw-r--r-- | src/loader/request.nim | 20 | ||||
-rw-r--r-- | src/types/blob.nim | 38 | ||||
-rw-r--r-- | src/types/formdata.nim | 25 | ||||
-rw-r--r-- | src/types/url.nim | 26 |
11 files changed, 167 insertions, 192 deletions
diff --git a/Makefile b/Makefile index c99165b4..6093c1f6 100644 --- a/Makefile +++ b/Makefile @@ -112,10 +112,9 @@ $(OUTDIR_CGI_BIN)/stbi: adapter/img/stbi.nim adapter/img/stb_image.c \ $(OUTDIR_CGI_BIN)/jebp: adapter/img/jebp.c adapter/img/jebp.h \ src/utils/sandbox.nim $(OUTDIR_CGI_BIN)/sixel: src/types/color.nim src/utils/sandbox.nim $(twtstr) -$(OUTDIR_CGI_BIN)/canvas: src/css/cssvalues.nim src/img/bitmap.nim \ - src/img/painter.nim src/img/path.nim src/io/bufreader.nim \ - src/types/color.nim src/types/line.nim src/utils/sandbox.nim \ - $(dynstream) +$(OUTDIR_CGI_BIN)/canvas: src/img/bitmap.nim src/img/painter.nim \ + src/img/path.nim src/io/bufreader.nim src/types/color.nim \ + src/types/line.nim src/utils/sandbox.nim $(dynstream) $(twtstr) $(OUTDIR_LIBEXEC)/urlenc: $(twtstr) $(OUTDIR_LIBEXEC)/gopher2html: adapter/gophertypes.nim $(twtstr) $(OUTDIR_LIBEXEC)/ansi2html: src/types/color.nim $(twtstr) diff --git a/adapter/img/canvas.nim b/adapter/img/canvas.nim index 2182e1d9..32d6d37a 100644 --- a/adapter/img/canvas.nim +++ b/adapter/img/canvas.nim @@ -10,7 +10,6 @@ import std/os import std/posix import std/strutils -import css/cssvalues import img/bitmap import img/painter import img/path @@ -121,7 +120,7 @@ proc main() = var text: string var x, y: float64 var color: ARGBColor - var align: CSSTextAlign + var align: CanvasTextAlign r.sread(text) r.sread(x) r.sread(y) diff --git a/src/html/dom.nim b/src/html/dom.nim index e46d0078..9fc393c0 100644 --- a/src/html/dom.nim +++ b/src/html/dom.nim @@ -360,7 +360,7 @@ type # CanvasPathDrawingStyles lineWidth: float64 # CanvasTextDrawingStyles - textAlign: CSSTextAlign + textAlign: CanvasTextAlign # CanvasPath path: Path @@ -595,7 +595,7 @@ proc strokePath(ctx: CanvasRenderingContext2D; path: Path; color: ARGBColor) = w.swrite(color) proc fillText(ctx: CanvasRenderingContext2D; text: string; x, y: float64; - color: ARGBColor; align: CSSTextAlign) = + color: ARGBColor; align: CanvasTextAlign) = if ctx.ps != nil: ctx.ps.withPacketWriter w: w.swrite(pcFillText) @@ -606,7 +606,7 @@ proc fillText(ctx: CanvasRenderingContext2D; text: string; x, y: float64; w.swrite(align) proc strokeText(ctx: CanvasRenderingContext2D; text: string; x, y: float64; - color: ARGBColor; align: CSSTextAlign) = + color: ARGBColor; align: CanvasTextAlign) = if ctx.ps != nil: ctx.ps.withPacketWriter w: w.swrite(pcStrokeText) @@ -826,22 +826,12 @@ proc getLineDash(ctx: CanvasRenderingContext2D): seq[float64] {.jsfunc.} = # CanvasTextDrawingStyles proc textAlign(ctx: CanvasRenderingContext2D): string {.jsfget.} = - case ctx.state.textAlign - of TextAlignStart: return "start" - of TextAlignEnd: return "end" - of TextAlignLeft: return "left" - of TextAlignRight: return "right" - of TextAlignCenter: return "center" - else: doAssert false + return $ctx.state.textAlign proc textAlign(ctx: CanvasRenderingContext2D; s: string) {.jsfset.} = - ctx.state.textAlign = case s - of "start": TextAlignStart - of "end": TextAlignEnd - of "left": TextAlignLeft - of "right": TextAlignRight - of "center": TextAlignCenter - else: ctx.state.textAlign + let x = parseEnumNoCase[CanvasTextAlign](s) + if x.isSome: + ctx.state.textAlign = x.get # CanvasPath proc closePath(ctx: CanvasRenderingContext2D) {.jsfunc.} = @@ -859,19 +849,30 @@ proc quadraticCurveTo(ctx: CanvasRenderingContext2D; cpx, cpy, x, proc arcTo(ctx: CanvasRenderingContext2D; x1, y1, x2, y2, radius: float64): Err[DOMException] {.jsfunc.} = - return ctx.state.path.arcTo(x1, y1, x2, y2, radius) + if radius < 0: + return errDOMException("Expected positive radius, but got negative", + "IndexSizeError") + ctx.state.path.arcTo(x1, y1, x2, y2, radius) + return ok() proc arc(ctx: CanvasRenderingContext2D; x, y, radius, startAngle, endAngle: float64; counterclockwise = false): Err[DOMException] {.jsfunc.} = - return ctx.state.path.arc(x, y, radius, startAngle, endAngle, - counterclockwise) + if radius < 0: + return errDOMException("Expected positive radius, but got negative", + "IndexSizeError") + ctx.state.path.arc(x, y, radius, startAngle, endAngle, counterclockwise) + return ok() proc ellipse(ctx: CanvasRenderingContext2D; x, y, radiusX, radiusY, rotation, startAngle, endAngle: float64; counterclockwise = false): Err[DOMException] {.jsfunc.} = - return ctx.state.path.ellipse(x, y, radiusX, radiusY, rotation, startAngle, - endAngle, counterclockwise) + if radiusX < 0 or radiusY < 0: + return errDOMException("Expected positive radius, but got negative", + "IndexSizeError") + ctx.state.path.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, + counterclockwise) + return ok() proc rect(ctx: CanvasRenderingContext2D; x, y, w, h: float64) {.jsfunc.} = ctx.state.path.rect(x, y, w, h) diff --git a/src/img/painter.nim b/src/img/painter.nim index 0479bd77..c86ad0a2 100644 --- a/src/img/painter.nim +++ b/src/img/painter.nim @@ -1,20 +1,27 @@ import std/algorithm import std/unicode -import css/cssvalues import img/bitmap import img/path import types/color import types/line import types/vector -type CanvasFillRule* = enum - cfrNonZero = "nonzero" - cfrEvenOdd = "evenodd" +type + CanvasFillRule* = enum + cfrNonZero = "nonzero" + cfrEvenOdd = "evenodd" -type PaintCommand* = enum - pcSetDimensions, pcFillRect, pcStrokeRect, pcFillPath, pcStrokePath, - pcFillText, pcStrokeText + PaintCommand* = enum + pcSetDimensions, pcFillRect, pcStrokeRect, pcFillPath, pcStrokePath, + pcFillText, pcStrokeText + + CanvasTextAlign* = enum + ctaStart = "start" + ctaEnd = "end" + ctaLeft = "left" + ctaRight = "right" + ctaCenter = "center" # https://en.wikipedia.org/wiki/Bresenham's_line_algorithm#All_cases proc plotLineLow(bmp: Bitmap; x1, y1, x2, y2: int; color: ARGBColor) = @@ -181,7 +188,7 @@ proc drawBitmap(a, b: Bitmap; p: Vector2D) = a.setpxb(ax, ay, b.getpx(x, y)) proc fillText*(bmp: Bitmap; text: string; x, y: float64; color: ARGBColor; - textAlign: CSSTextAlign) = + textAlign: CanvasTextAlign) = var w = 0f64 var glyphs: seq[Bitmap] = @[] for r in text.runes: @@ -191,15 +198,14 @@ proc fillText*(bmp: Bitmap; text: string; x, y: float64; color: ARGBColor; var x = x #TODO rtl case textAlign - of TextAlignLeft, TextAlignStart: discard - of TextAlignRight, TextAlignEnd: x -= w - of TextAlignCenter: x -= w / 2 - else: doAssert false + of ctaLeft, ctaStart: discard + of ctaRight, ctaEnd: x -= w + of ctaCenter: x -= w / 2 for glyph in glyphs: bmp.drawBitmap(glyph, Vector2D(x: x, y: y - 8)) x += float64(glyph.width) proc strokeText*(bmp: Bitmap; text: string; x, y: float64; color: ARGBColor; - textAlign: CSSTextAlign) = + textAlign: CanvasTextAlign) = #TODO bmp.fillText(text, x, y, color, textAlign) diff --git a/src/img/path.nim b/src/img/path.nim index 5c1ce680..c5db0bea 100644 --- a/src/img/path.nim +++ b/src/img/path.nim @@ -4,8 +4,6 @@ import std/math import types/line import types/vector -import js/domexception -import types/opt type Path* = ref object @@ -303,13 +301,10 @@ proc bezierCurveTo*(path: Path; cp0x, cp0y, cp1x, cp1y, x, y: float64) = let p = Vector2D(x: x, y: y) path.addBezierSegment(cp0, cp1, p) -proc arcTo*(path: Path; x1, y1, x2, y2, radius: float64): Err[DOMException] = +proc arcTo*(path: Path; x1, y1, x2, y2, radius: float64) = for v in [x1, y1, x2, y2, radius]: if classify(v) in {fcInf, fcNegInf, fcNan}: - return ok() - if radius < 0: - return errDOMException("Expected positive radius, but got negative", - "IndexSizeError") + return path.ensureSubpath(x1, y1) #TODO this should be transformed by the inverse of the transformation matrix let v0 = path.subpaths[^1].points[^1] @@ -333,7 +328,6 @@ proc arcTo*(path: Path; x1, y1, x2, y2, radius: float64): Err[DOMException] = ) path.addStraightSegment(tv0) path.addArcSegment(origin, tv2, radius, true) #TODO always inner? - return ok() func resolveEllipsePoint(o: Vector2D; angle, radiusX, radiusY, rotation: float64): Vector2D = @@ -350,13 +344,10 @@ func resolveEllipsePoint(o: Vector2D; angle, radiusX, radiusY, return Vector2D(x: relx, y: rely).rotate(rotation) + o proc arc*(path: Path; x, y, radius, startAngle, endAngle: float64; - counterclockwise: bool): Err[DOMException] = + counterclockwise: bool) = for v in [x, y, radius, startAngle, endAngle]: if classify(v) in {fcInf, fcNegInf, fcNan}: - return ok() - if radius < 0: - return errDOMException("Expected positive radius, but got negative", - "IndexSizeError") + return let o = Vector2D(x: x, y: y) var s = resolveEllipsePoint(o, startAngle, radius, radius, 0) var e = resolveEllipsePoint(o, endAngle, radius, radius, 0) @@ -369,16 +360,12 @@ proc arc*(path: Path; x, y, radius, startAngle, endAngle: float64; else: path.moveTo(s) path.addArcSegment(o, e, radius, abs(startAngle - endAngle) < PI) - return ok() proc ellipse*(path: Path; x, y, radiusX, radiusY, rotation, startAngle, - endAngle: float64; counterclockwise: bool): Err[DOMException] = + endAngle: float64; counterclockwise: bool) = for v in [x, y, radiusX, radiusY, rotation, startAngle, endAngle]: if classify(v) in {fcInf, fcNegInf, fcNan}: - return ok() - if radiusX < 0 or radiusY < 0: - return errDOMException("Expected positive radius, but got negative", - "IndexSizeError") + return let o = Vector2D(x: x, y: y) var s = resolveEllipsePoint(o, startAngle, radiusX, radiusY, rotation) var e = resolveEllipsePoint(o, endAngle, radiusX, radiusY, rotation) @@ -391,7 +378,6 @@ proc ellipse*(path: Path; x, y, radiusX, radiusY, rotation, startAngle, else: path.moveTo(s) path.addEllipseSegment(o, e, radiusX, radiusY) - return ok() proc rect*(path: Path; x, y, w, h: float64) = for v in [x, y, w, h]: diff --git a/src/io/bufreader.nim b/src/io/bufreader.nim index 8dc7b0a2..46f8e0f3 100644 --- a/src/io/bufreader.nim +++ b/src/io/bufreader.nim @@ -2,39 +2,29 @@ import std/options import std/sets import std/tables -import img/bitmap import io/dynstream -import loader/request -import types/blob import types/color -import types/formdata import types/opt -import types/url type BufferedReader* = object buffer: seq[uint8] bufIdx: int - recvAux: seq[FileHandle] #TODO assert on unused ones + recvAux*: seq[FileHandle] #TODO assert on unused ones proc sread*(reader: var BufferedReader; n: var SomeNumber) proc sread*[T](reader: var BufferedReader; s: var set[T]) proc sread*[T: enum](reader: var BufferedReader; x: var T) proc sread*(reader: var BufferedReader; s: var string) proc sread*(reader: var BufferedReader; b: var bool) -proc sread*(reader: var BufferedReader; url: var URL) proc sread*(reader: var BufferedReader; tup: var tuple) proc sread*[I, T](reader: var BufferedReader; a: var array[I, T]) proc sread*(reader: var BufferedReader; s: var seq) proc sread*[U, V](reader: var BufferedReader; t: var Table[U, V]) proc sread*(reader: var BufferedReader; obj: var object) proc sread*(reader: var BufferedReader; obj: var ref object) -proc sread*(reader: var BufferedReader; part: var FormDataEntry) -proc sread*(reader: var BufferedReader; blob: var Blob) proc sread*[T](reader: var BufferedReader; o: var Option[T]) proc sread*[T, E](reader: var BufferedReader; o: var Result[T, E]) -proc sread*(reader: var BufferedReader; c: var ARGBColor) {.inline.} -proc sread*(reader: var BufferedReader; o: var RequestBody) -proc sread*(reader: var BufferedReader; bmp: var NetworkBitmap) +proc sread*(reader: var BufferedReader; c: var ARGBColor) proc initReader*(stream: DynStream; len, auxLen: int): BufferedReader = assert len != 0 @@ -57,7 +47,7 @@ template withPacketReader*(stream: DynStream; r, body: untyped) = var r = stream.initPacketReader() body -proc readData(reader: var BufferedReader; buffer: pointer; len: int) = +proc readData*(reader: var BufferedReader; buffer: pointer; len: int) = assert reader.bufIdx + len <= reader.buffer.len copyMem(buffer, addr reader.buffer[reader.bufIdx], len) reader.bufIdx += len @@ -94,18 +84,6 @@ proc sread*(reader: var BufferedReader; b: var bool) = assert n == 0u8 b = false -proc sread*(reader: var BufferedReader; url: var URL) = - var s: string - reader.sread(s) - if s == "": - url = nil - else: - let x = newURL(s) - if x.isSome: - url = x.get - else: - url = nil - proc sread*(reader: var BufferedReader; tup: var tuple) = for f in tup.fields: reader.sread(f) @@ -142,38 +120,6 @@ proc sread*(reader: var BufferedReader; obj: var ref object) = new(obj) reader.sread(obj[]) -proc sread*(reader: var BufferedReader; part: var FormDataEntry) = - var isstr: bool - reader.sread(isstr) - if isstr: - part = FormDataEntry(isstr: true) - else: - part = FormDataEntry(isstr: false) - reader.sread(part.name) - reader.sread(part.filename) - if part.isstr: - reader.sread(part.svalue) - else: - reader.sread(part.value) - -proc sread*(reader: var BufferedReader; blob: var Blob) = - var isWebFile: bool - reader.sread(isWebFile) - blob = if isWebFile: WebFile() else: Blob() - if isWebFile: - reader.sread(WebFile(blob).name) - var hasFd: bool - reader.sread(hasFd) - if hasFd: - blob.fd = some(reader.recvAux.pop()) - reader.sread(blob.ctype) - reader.sread(blob.size) - if blob.size > 0: - let buffer = alloc(blob.size) - reader.readData(blob.buffer, int(blob.size)) - blob.buffer = buffer - blob.deallocFun = deallocBlob - proc sread*[T](reader: var BufferedReader; o: var Option[T]) = var x: bool reader.sread(x) @@ -204,21 +150,3 @@ proc sread*[T, E](reader: var BufferedReader; o: var Result[T, E]) = proc sread*(reader: var BufferedReader; c: var ARGBColor) = reader.sread(uint32(c)) - -proc sread*(reader: var BufferedReader; o: var RequestBody) = - var t: RequestBodyType - reader.sread(t) - o = RequestBody(t: t) - case t - of rbtNone: discard - of rbtString: reader.sread(o.s) - of rbtMultipart: reader.sread(o.multipart) - of rbtOutput: reader.sread(o.outputId) - -proc sread*(reader: var BufferedReader; bmp: var NetworkBitmap) = - bmp = NetworkBitmap() - reader.sread(bmp.width) - reader.sread(bmp.height) - reader.sread(bmp.cacheId) - reader.sread(bmp.imageId) - reader.sread(bmp.contentType) diff --git a/src/io/bufwriter.nim b/src/io/bufwriter.nim index ed4cb725..77b8ebd8 100644 --- a/src/io/bufwriter.nim +++ b/src/io/bufwriter.nim @@ -5,21 +5,16 @@ import std/options import std/sets import std/tables -import img/bitmap import io/dynstream -import loader/request -import types/blob import types/color -import types/formdata import types/opt -import types/url type BufferedWriter* = object stream: DynStream buffer: ptr UncheckedArray[uint8] bufSize: int bufLen: int - sendAux: seq[FileHandle] + sendAux*: seq[FileHandle] proc `=destroy`(writer: var BufferedWriter) = if writer.buffer != nil: @@ -31,20 +26,15 @@ proc swrite*[T](writer: var BufferedWriter; s: set[T]) proc swrite*[T: enum](writer: var BufferedWriter; x: T) proc swrite*(writer: var BufferedWriter; s: string) proc swrite*(writer: var BufferedWriter; b: bool) -proc swrite*(writer: var BufferedWriter; url: URL) proc swrite*(writer: var BufferedWriter; tup: tuple) proc swrite*[I, T](writer: var BufferedWriter; a: array[I, T]) proc swrite*[T](writer: var BufferedWriter; s: openArray[T]) proc swrite*[U, V](writer: var BufferedWriter; t: Table[U, V]) proc swrite*(writer: var BufferedWriter; obj: object) proc swrite*(writer: var BufferedWriter; obj: ref object) -proc swrite*(writer: var BufferedWriter; part: FormDataEntry) -proc swrite*(writer: var BufferedWriter; blob: Blob) proc swrite*[T](writer: var BufferedWriter; o: Option[T]) proc swrite*[T, E](writer: var BufferedWriter; o: Result[T, E]) -proc swrite*(writer: var BufferedWriter; c: ARGBColor) {.inline.} -proc swrite*(writer: var BufferedWriter; o: RequestBody) -proc swrite*(writer: var BufferedWriter; bmp: NetworkBitmap) +proc swrite*(writer: var BufferedWriter; c: ARGBColor) const InitLen = sizeof(int) * 2 const SizeInit = max(64, InitLen) @@ -81,7 +71,7 @@ template withPacketWriter*(stream: DynStream; w, body: untyped) = w.flush() w.deinit() -proc writeData(writer: var BufferedWriter; buffer: pointer; len: int) = +proc writeData*(writer: var BufferedWriter; buffer: pointer; len: int) = let targetLen = writer.bufLen + len let missing = targetLen - writer.bufSize if missing > 0: @@ -118,12 +108,6 @@ proc swrite*(writer: var BufferedWriter; b: bool) = else: writer.swrite(0u8) -proc swrite*(writer: var BufferedWriter; url: URL) = - if url != nil: - writer.swrite(url.serialize()) - else: - writer.swrite("") - proc swrite*(writer: var BufferedWriter; tup: tuple) = for f in tup.fields: writer.swrite(f) @@ -152,28 +136,6 @@ proc swrite*(writer: var BufferedWriter; obj: ref object) = if obj != nil: writer.swrite(obj[]) -proc swrite*(writer: var BufferedWriter; part: FormDataEntry) = - writer.swrite(part.isstr) - writer.swrite(part.name) - writer.swrite(part.filename) - if part.isstr: - writer.swrite(part.svalue) - else: - writer.swrite(part.value) - -#TODO clean up this mess -proc swrite*(writer: var BufferedWriter; blob: Blob) = - if blob.fd.isSome: - writer.sendAux.add(blob.fd.get) - writer.swrite(blob of WebFile) - if blob of WebFile: - writer.swrite(WebFile(blob).name) - writer.swrite(blob.fd.isSome) - writer.swrite(blob.ctype) - writer.swrite(blob.size) - if blob.size > 0: - writer.writeData(blob.buffer, int(blob.size)) - proc swrite*[T](writer: var BufferedWriter; o: Option[T]) = writer.swrite(o.isSome) if o.isSome: @@ -190,18 +152,3 @@ proc swrite*[T, E](writer: var BufferedWriter; o: Result[T, E]) = proc swrite*(writer: var BufferedWriter; c: ARGBColor) = writer.swrite(uint32(c)) - -proc swrite*(writer: var BufferedWriter; o: RequestBody) = - writer.swrite(o.t) - case o.t - of rbtNone: discard - of rbtString: writer.swrite(o.s) - of rbtMultipart: writer.swrite(o.multipart) - of rbtOutput: writer.swrite(o.outputId) - -proc swrite*(writer: var BufferedWriter; bmp: NetworkBitmap) = - writer.swrite(bmp.width) - writer.swrite(bmp.height) - writer.swrite(bmp.cacheId) - writer.swrite(bmp.imageId) - writer.swrite(bmp.contentType) diff --git a/src/loader/request.nim b/src/loader/request.nim index 2af5dcf3..c210898d 100644 --- a/src/loader/request.nim +++ b/src/loader/request.nim @@ -2,6 +2,8 @@ import std/options import std/tables import html/script +import io/bufreader +import io/bufwriter import loader/headers import monoucha/fromjs import monoucha/javascript @@ -90,6 +92,24 @@ type jsDestructor(JSRequest) +proc swrite*(writer: var BufferedWriter; o: RequestBody) = + writer.swrite(o.t) + case o.t + of rbtNone: discard + of rbtString: writer.swrite(o.s) + of rbtMultipart: writer.swrite(o.multipart) + of rbtOutput: writer.swrite(o.outputId) + +proc sread*(reader: var BufferedReader; o: var RequestBody) = + var t: RequestBodyType + reader.sread(t) + o = RequestBody(t: t) + case t + of rbtNone: discard + of rbtString: reader.sread(o.s) + of rbtMultipart: reader.sread(o.multipart) + of rbtOutput: reader.sread(o.outputId) + proc contentLength*(body: RequestBody): int = case body.t of rbtNone: return 0 diff --git a/src/types/blob.nim b/src/types/blob.nim index c0278bde..cc69fd7c 100644 --- a/src/types/blob.nim +++ b/src/types/blob.nim @@ -2,6 +2,8 @@ import std/options import std/posix import std/strutils +import io/bufreader +import io/bufwriter import monoucha/fromjs import monoucha/javascript import monoucha/jstypes @@ -25,6 +27,42 @@ type jsDestructor(Blob) jsDestructor(WebFile) +# Forward declarations +proc deallocBlob*(opaque, p: pointer) {.raises: [].} + +#TODO it would be nice if we had a separate fd type that does sendAux; +# this solution fails when blob isn't swritten by some module that does +# not import it (just as a transitive dependency). +proc swrite*(writer: var BufferedWriter; blob: Blob) = + if blob.fd.isSome: + writer.sendAux.add(blob.fd.get) + writer.swrite(blob of WebFile) + if blob of WebFile: + writer.swrite(WebFile(blob).name) + writer.swrite(blob.fd.isSome) + writer.swrite(blob.ctype) + writer.swrite(blob.size) + if blob.size > 0: + writer.writeData(blob.buffer, int(blob.size)) + +proc sread*(reader: var BufferedReader; blob: var Blob) = + var isWebFile: bool + reader.sread(isWebFile) + blob = if isWebFile: WebFile() else: Blob() + if isWebFile: + reader.sread(WebFile(blob).name) + var hasFd: bool + reader.sread(hasFd) + if hasFd: + blob.fd = some(reader.recvAux.pop()) + reader.sread(blob.ctype) + reader.sread(blob.size) + if blob.size > 0: + let buffer = alloc(blob.size) + reader.readData(blob.buffer, int(blob.size)) + blob.buffer = buffer + blob.deallocFun = deallocBlob + proc newBlob*(buffer: pointer; size: int; ctype: string; deallocFun: DeallocFun; opaque: pointer = nil): Blob = return Blob( diff --git a/src/types/formdata.nim b/src/types/formdata.nim index 9ce881f0..c57eda10 100644 --- a/src/types/formdata.nim +++ b/src/types/formdata.nim @@ -1,5 +1,7 @@ import std/strutils +import io/bufreader +import io/bufwriter import io/dynstream import monoucha/javascript import types/blob @@ -21,6 +23,29 @@ type jsDestructor(FormData) +proc swrite*(writer: var BufferedWriter; part: FormDataEntry) = + writer.swrite(part.isstr) + writer.swrite(part.name) + writer.swrite(part.filename) + if part.isstr: + writer.swrite(part.svalue) + else: + writer.swrite(part.value) + +proc sread*(reader: var BufferedReader; part: var FormDataEntry) = + var isstr: bool + reader.sread(isstr) + if isstr: + part = FormDataEntry(isstr: true) + else: + part = FormDataEntry(isstr: false) + reader.sread(part.name) + reader.sread(part.filename) + if part.isstr: + reader.sread(part.svalue) + else: + reader.sread(part.value) + iterator items*(this: FormData): FormDataEntry {.inline.} = for entry in this.entries: yield entry diff --git a/src/types/url.nim b/src/types/url.nim index 9e323847..b676a2b5 100644 --- a/src/types/url.nim +++ b/src/types/url.nim @@ -5,6 +5,8 @@ import std/strutils import std/tables import std/unicode +import io/bufreader +import io/bufwriter import lib/punycode import monoucha/fromjs import monoucha/javascript @@ -85,6 +87,30 @@ type jsDestructor(URL) jsDestructor(URLSearchParams) +# Forward declarations +proc parseURL*(input: string; base = none(URL); override = none(URLState)): + Option[URL] +func serialize*(url: URL; excludefragment = false; excludepassword = false): + string + +proc swrite*(writer: var BufferedWriter; url: URL) = + if url != nil: + writer.swrite(url.serialize()) + else: + writer.swrite("") + +proc sread*(reader: var BufferedReader; url: var URL) = + var s: string + reader.sread(s) + if s == "": + url = nil + else: + let x = parseURL(s) + if x.isSome: + url = x.get + else: + url = nil + const EmptyPath = URLPath(opaque: true, s: "") const EmptyHost = Host(t: htDomain, domain: "") |