http.ha (1814B)
1 use fmt; 2 use net; 3 use io; 4 use strings; 5 use strconv; 6 use encoding::utf8; 7 8 export type invalid = !void; 9 10 export type response = struct { 11 status: int, 12 attributes: [][]str 13 }; 14 15 export fn get(sock: io::handle, resource: str) (str | io::error | utf8::invalid) = { 16 let req = fmt::asprintf("GET {} HTTP/1.1\r\nUser-Agent: curl/8.6.0\r\n\r\n", resource)!; 17 defer free(req); 18 let utf8 = strings::toutf8(req); 19 20 match (io::write(sock, utf8)) { 21 case let e: io::error => return e; 22 case => yield; 23 }; 24 25 let res: []u8 = match(io::drain(sock)) { 26 case let buf: []u8 => yield buf; 27 case let e: io::error => return e; 28 }; 29 30 return strings::fromutf8(res); 31 }; 32 33 export fn freeres(res: *response) void = { 34 for (let attribute .. res.attributes) { 35 strings::freeall(attribute); 36 }; 37 }; 38 39 export fn parseres(res: str, html: *str) (response | invalid) = { 40 let header = strings::index(res, "\r\n\r\n") as size; 41 let lines = strings::split(strings::sub(res, 0, header), "\r\n")!; 42 defer free(lines); 43 44 let tok = &strings::tokenize(lines[0], " "); 45 match (strings::next_token(tok)) { 46 case done => return invalid; 47 case => yield; 48 }; 49 let s = match(strings::next_token(tok)) { 50 case let s: str => yield match (strconv::stoi(s)) { 51 case let i: int => yield i; 52 case => return invalid; 53 }; 54 }; 55 56 let response = response { 57 status = s, 58 attributes = [], 59 }; 60 61 let i = 0z; 62 for (let line .. lines[1..]) { 63 let split = match (strings::splitn(line, ": ", 2)) { 64 case let s: []str => yield s; 65 case nomem => fmt::fatal("Out of memory!"); 66 }; 67 if (len(split) >= 2) { 68 split[0] = strings::ltrim(split[0]); 69 split[1] = strings::ltrim(split[1]); 70 append(response.attributes, strings::dupall(split) as []str)!; 71 i += 1; 72 }; 73 74 free(split); 75 }; 76 77 *html = strings::sub(res, header + 4, strings::end); 78 return response; 79 };