diff --git a/bench.mojo b/bench.mojo index 7b0b0d02..1a676c8b 100644 --- a/bench.mojo +++ b/bench.mojo @@ -15,7 +15,7 @@ fn main(): try: var server = SysServer() let handler = TechEmpowerRouter() - server.listen_and_serve("0.0.0.0:8080", handler) + server.listen_and_serve_async("0.0.0.0:8080", handler) except e: print("Error starting server: " + e.__str__()) return diff --git a/external/b64.mojo b/external/b64.mojo new file mode 100644 index 00000000..6d678ae0 --- /dev/null +++ b/external/b64.mojo @@ -0,0 +1,432 @@ +from math import bitcast +from math import rotate_bits_left + + +alias cpad = "=".data().bitcast[DType.uint8]()[0] +alias e0 = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ" + "aaaabbbbccccddddeeeeffffgggghhhhiiiijjjjkkkkllllmmmmnnnnooooppppqqqqrrrrssssttttuuuuvvvvwwwwxxxxyyyyzzzz" + "0000111122223333444455556666777788889999++++////".data().bitcast[DType.uint8]() +alias e1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".data().bitcast[DType.uint8]() +alias BADCHAR = UInt32(0x01FFFFFF) + +alias d0 = compute_d0() + +fn compute_d0() -> DTypePointer[DType.uint32]: + let d = SIMD[DType.uint32, 256]( + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x000000f8, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000fc, + 0x000000d0, 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4, + 0x000000e8, 0x000000ec, 0x000000f0, 0x000000f4, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, + 0x00000004, 0x00000008, 0x0000000c, 0x00000010, 0x00000014, 0x00000018, + 0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c, 0x00000030, + 0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048, + 0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060, + 0x00000064, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x00000068, 0x0000006c, 0x00000070, 0x00000074, 0x00000078, + 0x0000007c, 0x00000080, 0x00000084, 0x00000088, 0x0000008c, 0x00000090, + 0x00000094, 0x00000098, 0x0000009c, 0x000000a0, 0x000000a4, 0x000000a8, + 0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc, 0x000000c0, + 0x000000c4, 0x000000c8, 0x000000cc, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff + ) + let p = DTypePointer[DType.uint32].alloc(256) + p.simd_store(d) + return p +alias d1 = compute_d1() + +fn compute_d1() -> DTypePointer[DType.uint32]: + let d = SIMD[DType.uint32, 256]( + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x0000e003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000f003, + 0x00004003, 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003, + 0x0000a003, 0x0000b003, 0x0000c003, 0x0000d003, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, + 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, + 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, + 0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001, + 0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001, + 0x00009001, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x0000a001, 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001, + 0x0000f001, 0x00000002, 0x00001002, 0x00002002, 0x00003002, 0x00004002, + 0x00005002, 0x00006002, 0x00007002, 0x00008002, 0x00009002, 0x0000a002, + 0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002, 0x00000003, + 0x00001003, 0x00002003, 0x00003003, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff + ) + let p = DTypePointer[DType.uint32].alloc(256) + p.simd_store(d) + return p + +alias d2 = compute_d2() + +fn compute_d2() -> DTypePointer[DType.uint32]: + let d = SIMD[DType.uint32, 256]( + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x00800f00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00c00f00, + 0x00000d00, 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00, + 0x00800e00, 0x00c00e00, 0x00000f00, 0x00400f00, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, + 0x00400000, 0x00800000, 0x00c00000, 0x00000100, 0x00400100, 0x00800100, + 0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200, 0x00000300, + 0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400, + 0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600, + 0x00400600, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x00800600, 0x00c00600, 0x00000700, 0x00400700, 0x00800700, + 0x00c00700, 0x00000800, 0x00400800, 0x00800800, 0x00c00800, 0x00000900, + 0x00400900, 0x00800900, 0x00c00900, 0x00000a00, 0x00400a00, 0x00800a00, + 0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00, 0x00000c00, + 0x00400c00, 0x00800c00, 0x00c00c00, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff + ) + let p = DTypePointer[DType.uint32].alloc(256) + p.simd_store(d) + return p + +alias d3 = compute_d3() + +fn compute_d3() -> DTypePointer[DType.uint32]: + let d = SIMD[DType.uint32, 256]( + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x003e0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003f0000, + 0x00340000, 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000, + 0x003a0000, 0x003b0000, 0x003c0000, 0x003d0000, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, + 0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050000, 0x00060000, + 0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000, 0x000c0000, + 0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000, + 0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000, + 0x00190000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x001a0000, 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000, + 0x001f0000, 0x00200000, 0x00210000, 0x00220000, 0x00230000, 0x00240000, + 0x00250000, 0x00260000, 0x00270000, 0x00280000, 0x00290000, 0x002a0000, + 0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000, 0x00300000, + 0x00310000, 0x00320000, 0x00330000, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, + 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff + ) + let p = DTypePointer[DType.uint32].alloc(256) + p.simd_store(d) + return p + +@always_inline +fn decode[zero_terminated: Bool = False](input: String) raises -> (DTypePointer[DType.uint8], Int): + var input_size = len(input) + var input_pointer = input._as_ptr().bitcast[DType.uint8]() + if input_size == 0: + return DTypePointer[DType.uint8](), 0 + + if input_size & 3 != 0: + raise "We do not support unpadded base64 strings" + + # input size without padding + input_size -= (input_pointer.load(input_size - 2) == cpad).to_int() + (input_pointer.load(input_size - 1) == cpad).to_int() + + var result_size = (input_size >> 2) * 3 + @parameter + if zero_terminated: + result_size += 1 + let result = DTypePointer[DType.uint8].alloc(result_size) + + let leftover = input_size & 3 + let chunks = input_size >> 2 + + var bad_char = False + var destination = result + for i in range(chunks): + let x = d0[input_pointer[0].to_int()] | d1[input_pointer[1].to_int()] | d2[input_pointer[2].to_int()] | d3[input_pointer[3].to_int()] + bad_char = bad_char | x >= BADCHAR + let xu8 = bitcast[DType.uint8, 4](x) + destination.store(xu8[0]) + destination.store(1, xu8[1]) + destination.store(2, xu8[2]) + destination = destination.offset(3) + input_pointer = input_pointer.offset(4) + + if leftover == 2: + let x = d0[input_pointer[0].to_int()] | d1[input_pointer[1].to_int()] + bad_char = bad_char | x >= BADCHAR + let xu8 = bitcast[DType.uint8, 4](x) + destination.store(xu8[0]) + result_size += 1 + elif leftover == 3: + let x = d0[input_pointer[0].to_int()] | d1[input_pointer[1].to_int()] | d2[input_pointer[2].to_int()] + bad_char = bad_char | x >= BADCHAR + let xu8 = bitcast[DType.uint8, 4](x) + destination.store(xu8[0]) + destination.store(1, xu8[1]) + result_size += 2 + + if bad_char: + raise "Could not decode. Bad char was identified" + + @parameter + if zero_terminated: + result[result_size - 1] = 0 + return result, result_size + +@always_inline +fn _encode( + input: DTypePointer[DType.uint8], length: Int, output: DTypePointer[DType.uint8] +): + var processed = 0 + var p = output + if length > 2: + for i in range(0, length - 2, 3): + let t1 = input.load(i).to_int() + let t2 = input.load(i + 1).to_int() + let t3 = input.load(i + 2).to_int() + let bytes = SIMD[DType.uint8, 4]( + e0.load(t1), + e1.load(((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)), + e1.load(((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)), + e1.load(t3), + ) + p.simd_nt_store(bytes) + p = p.offset(4) + processed = i + 3 + + let rest = length - processed + if rest == 1: + let t1 = input.load(processed).to_int() + let bytes = SIMD[DType.uint8, 4]( + e0.load(t1), e1.load(((t1 & 0x03) << 4)), cpad, cpad + ) + p.simd_nt_store(bytes) + elif rest == 2: + let t1 = input.load(processed).to_int() + let t2 = input.load(processed + 1).to_int() + let bytes = SIMD[DType.uint8, 4]( + e0.load(t1), + e1.load(((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)), + e1.load(((t2 & 0x0F) << 2)), + cpad, + ) + p.simd_nt_store(bytes) + + +@always_inline +fn encode(input: StringLiteral) -> String: + return encode(input.data().bitcast[DType.uint8](), len(input)) + + +@always_inline +fn encode(input: String) -> String: + return encode(input._as_ptr().bitcast[DType.uint8](), len(input)) + + +@always_inline +fn encode(input: Tensor) -> String: + return encode(input.data().bitcast[DType.uint8](), input.bytecount()) + + +@always_inline +fn encode(input: DTypePointer[DType.uint8], length: Int) -> String: + let data = input + let result_size = (length + 2) // 3 * 4 + 1 + let result = DTypePointer[DType.int8].aligned_alloc(4, result_size) + var offset = 0 + var cursor = result.bitcast[DType.uint8]() + alias simd_width = 32 + while length - offset >= simd_width: + let a = data.simd_load[simd_width](offset) + # aaaaaabb bbbbcccc ccdddddd ________ + let b = a.shuffle[ + 1, + 0, + 2, + 1, + 4, + 3, + 5, + 4, + 7, + 6, + 8, + 7, + 10, + 9, + 11, + 10, + 13, + 12, + 14, + 13, + 16, + 15, + 17, + 16, + 19, + 18, + 20, + 19, + 22, + 21, + 23, + 22, + ]() + # bbbbcccc aaaaaabb ccdddddd bbbbcccc + + offset += (simd_width >> 2) * 3 + + let c = bitcast[DType.uint16, simd_width >> 1](b) + + let d = c.deinterleave() + # d[0] = bbbbcccc aaaaaabb + # d[1] = ccdddddd bbbbcccc + + # TODO: this implementaiton is for little endian only add big endian support + + let d1 = rotate_bits_left[6](d[0]).cast[DType.uint8]() + # d1 = ccaaaaaa + let d2 = rotate_bits_left[12](d[0]).cast[DType.uint8]() + # d2 = aabbbbbb + let d3 = rotate_bits_left[10](d[1]).cast[DType.uint8]() + # d3 = bbcccccc + let d4 = d[1].cast[DType.uint8]() + # d4 = ccdddddd + + let e1 = d1.interleave(d3) + # e1 = ccaaaaaa bbcccccc + let e2 = d2.interleave(d4) + # e2 = aabbbbbb ccdddddd + let e3 = e1.interleave(e2) & 0b0011_1111 + # e3 = 00aaaaaa 00bbbbbb 00cccccc 00dddddd + + let upper = e3 < 26 + let lower = (e3 > 25) & (e3 < 52) + let nums = (e3 > 51) & (e3 < 62) + let plus = e3 == 62 + let slash = e3 == 63 + + let f1 = upper.select(e3 + 65, 0) + let f2 = lower.select(e3 + 71, 0) + let f3 = nums.select(e3 - 4, 0) + let f4 = plus.select(e3 - 19, 0) + let f5 = slash.select(e3 - 16, 0) + + # 0 .. 25 -> 65 .. 90 (+65) A .. Z + # 26 .. 51 -> 97 .. 122 (+71) a .. z + # 52 .. 61 -> 48 .. 57 (-4) 0 .. 9 + # 62 -> 43 (-19) + + # 63 -> 47 (-16) / + + cursor.simd_nt_store(0, f1 + f2 + f3 + f4 + f5) + + cursor = cursor.offset(simd_width) + + if length > offset: + _encode(data.offset(offset), length - offset, cursor) + + result.store(result_size - 1, 0) + return String(result, result_size) diff --git a/lightbug_http/io/bytes.mojo b/lightbug_http/io/bytes.mojo index 185317ea..fe215afc 100644 --- a/lightbug_http/io/bytes.mojo +++ b/lightbug_http/io/bytes.mojo @@ -1,6 +1,110 @@ from python import PythonObject +from base64 import b64encode +from memory.unsafe import bitcast +alias ByteDType = DType.int8 alias Bytes = DynamicVector[Int8] +alias Byte = Int8 + + +fn to_bytes(string: String) -> Bytes: + return b64encode(string)._buffer + + +fn to_bytes[type: DType, nelts: Int = 1](simd: SIMD[type, nelts]) -> Bytes: + let simd_bytes = bitcast[ByteDType, nelts * sizeof[type](), type, nelts](simd) + + var bytes = Bytes(nelts * sizeof[type]()) + + @unroll + for i in range(nelts * sizeof[type]()): + bytes.append(simd_bytes[i]) + + return bytes + + +fn to_string(bytes: Bytes) -> String: + return b64decode(bytes) + + +fn rstrip_unsafe(content: String, chars: String = " ") -> String: + var strip_pos: Int = len(content) + for i in range(len(content)): + let c = content[len(content) - i - 1 : len(content) - i] + if chars.find(c) == -1: + strip_pos = len(content) - i + break + + return content[:strip_pos] + + +# Temporary until stdlib base64 decode is implemented +fn b64decode(s: String) -> String: + alias base64: String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + + let padding = s.count("=") + + let s_strip = rstrip_unsafe(s, "=") + + # base64 decode + var binary_string: String = "" + for i in range(len(s_strip)): + let index: Byte = base64.find(s_strip[i : i + 1]) + binary_string += byte_to_binary_string(index) + + if padding: + binary_string = binary_string[: -padding * 2] + + var decoded_string: String = "" + for i in range(0, len(binary_string), 8): + let byte = binary_string[i : i + 8] + decoded_string += chr(binary_string_to_byte(byte).to_int()) + + return decoded_string + + +fn byte_to_binary_string(byte: Byte) -> String: + var binary_string: String = "" + for i in range(8): + let bit = (byte >> i) & 1 + binary_string += String(bit) + + # find significant bits + var significant_binary_string: String = "" + var found_significant_bit: Bool = False + for i in range(len(binary_string)): + let bit = binary_string[len(binary_string) - i - 1 : len(binary_string) - i] + if bit == "1": + found_significant_bit = True + if found_significant_bit: + significant_binary_string += bit + + # left pad to 6 bits if less than 6 bits + if len(significant_binary_string) < 6: + let padding = 6 - len(significant_binary_string) + for i in range(padding): + significant_binary_string = "0" + significant_binary_string + + return significant_binary_string + + +fn binary_string_to_byte(binary_string: String) -> Byte: + var total = 0 + let length = len(binary_string) + for i in range(length): + # Get the value at the current position (0 or 1) + let bit = binary_string[length - 1 - i] + + let bit_value: Int + if bit == "1": + bit_value = 1 + else: + bit_value = 0 + + # Add to the total, considering its position (2^i) + total += bit_value * (2**i) + + return total @value diff --git a/lightbug_http/strings.mojo b/lightbug_http/strings.mojo index 4bcaa58e..0de99375 100644 --- a/lightbug_http/strings.mojo +++ b/lightbug_http/strings.mojo @@ -12,6 +12,15 @@ alias rChar = String("\r")._buffer alias nChar = String("\n")._buffer +struct S[lifetime: MutLifetime]: + var s: Reference[String, __mlir_attr.`1: i1`, lifetime] # zero is immut + + fn __init__( + inout self, s: Reference[String, __mlir_attr.`1: i1`, lifetime] + ) -> None: + self.s = s + + # TODO: tuples don't work with strings in Mojo currently, to be replaced with a tuple @value struct TwoLines: diff --git a/lightbug_http/sys/net.mojo b/lightbug_http/sys/net.mojo index dbb1ad79..2c5971a1 100644 --- a/lightbug_http/sys/net.mojo +++ b/lightbug_http/sys/net.mojo @@ -9,7 +9,7 @@ from lightbug_http.net import ( default_tcp_keep_alive, ) from lightbug_http.strings import NetworkType -from lightbug_http.io.bytes import Bytes +from lightbug_http.io.bytes import Bytes, to_string, to_bytes, b64decode from lightbug_http.io.sync import Duration from external.libc import ( c_void, @@ -24,6 +24,7 @@ from external.libc import ( SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR, + O_NONBLOCK, SHUT_RDWR, htons, inet_pton, @@ -38,6 +39,9 @@ from external.libc import ( shutdown, close, ) +from external.b64 import encode as b64_encode + +# from external.b64 import decode as b64_decode @value @@ -57,7 +61,7 @@ struct SysListener(Listener): self.__addr = addr self.fd = fd - @always_inline + # @always_inline fn accept[T: Connection](self) raises -> T: let their_addr_ptr = Pointer[sockaddr].alloc(1) var sin_size = socklen_t(sizeof[socklen_t]()) @@ -162,12 +166,40 @@ struct SysConnection(Connection): buf = bytes_str._buffer return bytes_recv + async fn read_async(self, inout buf: Bytes) raises -> Int: + @parameter + async fn task() -> Int: + try: + _ = self.read(buf) + return buf[0].__int__() + except e: + print("Failed to read from connection: " + e.__str__()) + return -1 + + let routine: Coroutine[Int] = task() + return await routine + fn write(self, buf: Bytes) raises -> Int: let msg = String(buf) + print("Sending response: " + msg) if send(self.fd, to_char_ptr(msg).bitcast[c_void](), len(msg), 0) == -1: print("Failed to send response") return len(buf) + # This has to be a def for now because of a weird bug in the Mojo compiler + async def write_async(self, buf: Bytes) -> Int: + @parameter + async def task(task_buf: Bytes) -> Int: + try: + let write_len = self.write(task_buf) + return write_len + except e: + print("Failed to write to connection: " + e.__str__()) + return -1 + + let routine: RaisingCoroutine[Int] = task(buf) + return await routine + fn close(self) raises: _ = shutdown(self.fd, SHUT_RDWR) let close_status = close(self.fd) diff --git a/lightbug_http/sys/server.mojo b/lightbug_http/sys/server.mojo index b2f23cad..127d1523 100644 --- a/lightbug_http/sys/server.mojo +++ b/lightbug_http/sys/server.mojo @@ -6,9 +6,10 @@ from lightbug_http.header import RequestHeader from lightbug_http.sys.net import SysListener, SysConnection, SysNet from lightbug_http.service import HTTPService from lightbug_http.io.sync import Duration -from lightbug_http.io.bytes import Bytes +from lightbug_http.io.bytes import Bytes, to_bytes, to_string from lightbug_http.error import ErrorHandler -from lightbug_http.strings import next_line, NetworkType +from lightbug_http.strings import next_line, NetworkType, S +from external.b64 import encode as b64_encode struct SysServer: @@ -54,10 +55,89 @@ struct SysServer: let listener = __net.listen(NetworkType.tcp4.value, address) self.serve(listener, handler) - fn serve[T: HTTPService](inout self, ln: SysListener, handler: T) raises -> None: + fn listen_and_serve_async[ + T: HTTPService + ](inout self, address: String, handler: T) raises -> None: + var __net = SysNet() + let listener = __net.listen(NetworkType.tcp4.value, address) + self.serve_async(listener, handler) + + fn serve_async[ + T: HTTPService + ](inout self, ln: SysListener, handler: T) raises -> None: + self.ln = ln # let max_worker_count = self.get_concurrency() # TODO: logic for non-blocking read and write here, see for example https://github.com/valyala/fasthttp/blob/9ba16466dfd5d83e2e6a005576ee0d8e127457e2/server.go#L1789 + async fn handle_connection(conn: SysConnection, handler: T) -> None: + var buf = Bytes() + try: + let read_len = await conn.read_async(buf) + except e: + try: + conn.close() + except e: + print("Failed to close connection") + print("Failed to read from connection") + try: + let first_line_and_headers = next_line(buf) + let request_line = first_line_and_headers.first_line + let rest_of_headers = first_line_and_headers.rest + + var uri = URI(request_line) + try: + uri.parse() + except: + try: + conn.close() + except e: + print("Failed to close connection") + print("Failed to parse request line") + + var header = RequestHeader(buf) + try: + header.parse() + except: + try: + conn.close() + except e: + print("Failed to close connection") + print("Failed to parse request header") + + let res = handler.func( + HTTPRequest( + uri, + buf, + header, + ) + ) + var res_encoded = encode(res) + try: + _ = await conn.write_async(res_encoded) + except e: + print("Ooph! " + e.__str__()) + try: + conn.close() + except e: + print("Failed to close connection") + print("Failed to read from connection") + try: + conn.close() + except e: + print("Failed to close connection") + except e: + print("Failed to parse request line") + try: + conn.close() + except e: + print("Failed to close connection") + + while True: + let conn = self.ln.accept[SysConnection]() + let coroutine: Coroutine[NoneType] = handle_connection(conn, handler) + _ = coroutine() # Execute the coroutine synchronously + + fn serve[T: HTTPService](inout self, ln: SysListener, handler: T) raises -> None: self.ln = ln while True: diff --git a/lightbug_http/tests/utils.mojo b/lightbug_http/tests/utils.mojo index 6b3e5edb..6953ed2d 100644 --- a/lightbug_http/tests/utils.mojo +++ b/lightbug_http/tests/utils.mojo @@ -11,7 +11,7 @@ from lightbug_http.client import Client alias default_server_host = "localhost" alias default_server_port = 8080 -alias default_server_conn_string = "http://" + default_server_host + ":" + default_server_port.__str__() +alias default_server_conn_string = String("http://localhost:8080") alias getRequest = String( "GET /foobar?baz HTTP/1.1\r\nHost: google.com\r\nUser-Agent: aaa/bbb/ccc/ddd/eee" diff --git a/lightbug_http/uri.mojo b/lightbug_http/uri.mojo index 21f5e6ed..11aaa900 100644 --- a/lightbug_http/uri.mojo +++ b/lightbug_http/uri.mojo @@ -8,7 +8,6 @@ from lightbug_http.strings import ( ) -# TODO: convenience type, not currently used properly but will be helpful in the future @value struct URI: var __path_original: Bytes