diff --git a/examples/http_client.js b/examples/http_client.js index 35bf4fe..33a348f 100644 --- a/examples/http_client.js +++ b/examples/http_client.js @@ -2,18 +2,24 @@ ///@ts-check /// /// +/// import * as os from "os"; +import * as std from "std"; + /** @template T @param {os.Result} result */ function must(result) { - if (typeof result === "number" && result < 0) throw result; + if (typeof result === "number" && result < 0) throw new Error(std.strerror(-result)); return /** @type {T} */ (result) } - -const sockfd = must(os.socket(os.AF_INET, os.SOCK_STREAM)); -const addr = os.getaddrinfo("bellard.org",'80').find(a => a.family == os.AF_INET); +//USAGE: client.js wttr.in/paris +const uriRegexp = /^(?[A-Za-z0-9\-\.]+)(?:[0-9]+)?(?.*)$/; +const { host = "bellard.org", port = ":80", query = "/" } = scriptArgs[1]?.match(uriRegexp)?.groups || {}; +console.log("sending GET on",{ host, port, query }) +const [addr] = must(os.getaddrinfo(host, { service: port.slice(1) })); +const sockfd = must(os.socket(addr.family, addr.socktype)); await os.connect(sockfd, addr); -const httpReq = Uint8Array.from("GET / HTTP/1.0\r\n\r\n", c => c.charCodeAt(0)) +const httpReq = Uint8Array.from(`GET ${query||'/'} HTTP/1.0\r\nHost: ${host}\r\nUser-Agent: curl\r\n\r\n`, c => c.charCodeAt(0)) must(await os.send(sockfd, httpReq.buffer) > 0); const chunk = new Uint8Array(512); const recvd = await os.recv(sockfd, chunk.buffer); -console.log([...chunk.slice(0,recvd)].map(c => String.fromCharCode(c)).join('')); +console.log([...chunk.slice(0, recvd)].map(c => String.fromCharCode(c)).join('')); diff --git a/examples/http_server.js b/examples/http_server.js index a4d63aa..b38265f 100755 --- a/examples/http_server.js +++ b/examples/http_server.js @@ -2,7 +2,9 @@ ///@ts-check /// /// +/// import * as os from "os"; +import * as std from "std";// for std.strerror const MIMES = new Map([ ['html', 'text/html'], @@ -17,7 +19,7 @@ const MIMES = new Map([ ]); /** @template T @param {os.Result} result */ function must(result) { - if (typeof result === "number" && result < 0) throw result; + if (typeof result === "number" && result < 0) throw new Error(std.strerror(-result)); return /** @type {T} */ (result) } /**@param {os.FileDescriptor} fd */ @@ -40,7 +42,7 @@ function sendLines(fd, lines) { } //USAGE: qjs http_server.js [PORT=8080 [HOST=localhost]] const [port = "8080", host = "localhost"] = scriptArgs.slice(1); -const ai = os.getaddrinfo(host, port).find(a => a.family == os.AF_INET); +const [ai] = must(os.getaddrinfo(host, { service: port })); //if (!ai.length) throw `Unable to getaddrinfo(${host}, ${port})`; const sock_srv = must(os.socket(os.AF_INET, os.SOCK_STREAM)); must(os.setsockopt(sock_srv, os.SO_REUSEADDR, new Uint32Array([1]).buffer)); diff --git a/quickjs-libc.c b/quickjs-libc.c index 8786157..fb0f3e1 100644 --- a/quickjs-libc.c +++ b/quickjs-libc.c @@ -3710,27 +3710,42 @@ static JSValue js_os_get_setsockopt(JSContext *ctx, JSValueConst this_val, static JSValue js_os_getaddrinfo(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) { - int ret; - socklen_t objLen; - JSValue obj, addrObj; - const char* node = NULL; + int ret = -1; + if (!JS_IsString(argv[0])) + return JS_EXCEPTION; + const char* node = JS_ToCString(ctx, argv[0]); + const char* service = NULL; - struct addrinfo *ai,*it; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + if (!JS_IsNull(argv[1]) && JS_IsObject(argv[1])) { + JSValue prop_service = JS_GetPropertyStr(ctx, argv[1], "service"); + JSValue prop_family = JS_GetPropertyStr(ctx, argv[1], "family"); + JSValue prop_socktype = JS_GetPropertyStr(ctx, argv[1], "socktype"); + if (JS_IsException(prop_service) || + JS_IsException(prop_family) || + JS_IsException(prop_socktype)) + goto fail; + if (!JS_IsUndefined(prop_service)) + service = JS_ToCString(ctx, prop_service); + if (!JS_IsUndefined(prop_family)) + JS_ToInt32(ctx, &hints.ai_family, prop_family); + if (!JS_IsUndefined(prop_socktype)) + JS_ToInt32(ctx, &hints.ai_socktype, prop_socktype); + } - if (!JS_IsNull(argv[0]) && !JS_IsUndefined(argv[0])) - node = JS_ToCString(ctx, argv[0]); - - service = JS_ToCString(ctx, argv[1]); - if (!service) - goto fail; - - ret = js_get_sockerrno(getaddrinfo(node, service, NULL, &ai)); + struct addrinfo *ai; + ret = js_get_sockerrno(getaddrinfo(node, service, &hints, &ai)); if (ret) goto fail; - obj = JS_NewArray(ctx); + struct addrinfo *it; + socklen_t objLen; + JSValue obj = JS_NewArray(ctx); for (objLen = 0, it = ai; it; it = it->ai_next, objLen++) { - addrObj = JS_ToSockaddrObj(ctx,(struct sockaddr_storage *)it->ai_addr); + JSValue addrObj = JS_ToSockaddrObj(ctx,(struct sockaddr_storage *)it->ai_addr); + JSValue prop_socktype = JS_NewUint32(ctx, it->ai_socktype); + JS_DefinePropertyValueStr(ctx, addrObj, "socktype", prop_socktype, JS_PROP_C_W_E); JS_SetPropertyUint32(ctx,obj,objLen,addrObj); } @@ -3742,7 +3757,7 @@ fail: JS_FreeValue(ctx, obj); JS_FreeCString(ctx, service); JS_FreeCString(ctx, node); - return JS_EXCEPTION; + return JS_NewInt32(ctx, ret); } static JSValue js_os_bind(JSContext *ctx, JSValueConst this_val,