mirror of
https://github.com/ading2210/libcurl.js.git
synced 2025-05-13 22:40:01 -04:00
create session class and refactor js to use it
This commit is contained in:
parent
a282734c13
commit
0a5ace96fb
14 changed files with 359 additions and 192 deletions
|
@ -82,17 +82,22 @@ WISP_VERSION=$(cat $WISP_CLIENT/package.json | jq -r '.version')
|
||||||
sed -i "s/__wisp_version__/$WISP_VERSION/" $OUT_FILE
|
sed -i "s/__wisp_version__/$WISP_VERSION/" $OUT_FILE
|
||||||
|
|
||||||
|
|
||||||
#add extra libraries
|
#js files are inserted in reverse order
|
||||||
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/copyright.js" $OUT_FILE
|
|
||||||
sed -i "/__extra_libraries__/r $WISP_CLIENT/polyfill.js" $OUT_FILE
|
|
||||||
sed -i "/__extra_libraries__/r $WISP_CLIENT/wisp.js" $OUT_FILE
|
|
||||||
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/messages.js" $OUT_FILE
|
|
||||||
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/tls_socket.js" $OUT_FILE
|
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/tls_socket.js" $OUT_FILE
|
||||||
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/websocket.js" $OUT_FILE
|
|
||||||
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/ws_polyfill.js" $OUT_FILE
|
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/ws_polyfill.js" $OUT_FILE
|
||||||
|
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/websocket.js" $OUT_FILE
|
||||||
|
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/http.js" $OUT_FILE
|
||||||
|
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/session.js" $OUT_FILE
|
||||||
|
|
||||||
|
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/copyright.js" $OUT_FILE
|
||||||
|
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/messages.js" $OUT_FILE
|
||||||
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/util.js" $OUT_FILE
|
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/util.js" $OUT_FILE
|
||||||
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/logger.js" $OUT_FILE
|
sed -i "/__extra_libraries__/r $JAVSCRIPT_DIR/logger.js" $OUT_FILE
|
||||||
|
|
||||||
|
sed -i "/__extra_libraries__/r $WISP_CLIENT/polyfill.js" $OUT_FILE
|
||||||
|
sed -i "/__extra_libraries__/r $WISP_CLIENT/wisp.js" $OUT_FILE
|
||||||
|
|
||||||
|
|
||||||
#apply patches
|
#apply patches
|
||||||
python3 tools/patch_js.py $FRAGMENTS_DIR $OUT_FILE
|
python3 tools/patch_js.py $FRAGMENTS_DIR $OUT_FILE
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
init_curl
|
init_curl
|
||||||
start_request
|
session_create
|
||||||
cleanup_handle
|
session_perform
|
||||||
create_handle
|
session_set_options
|
||||||
tick_request
|
session_add_request
|
||||||
active_requests
|
session_get_active
|
||||||
|
session_remove_request
|
||||||
|
session_cleanup
|
||||||
|
|
||||||
|
create_request
|
||||||
get_version
|
get_version
|
||||||
get_cacert
|
get_cacert
|
||||||
get_error_str
|
get_error_str
|
||||||
|
|
|
@ -27,7 +27,7 @@ class FTPSession {
|
||||||
};
|
};
|
||||||
let headers_callback = () => {this.headers_callback()};
|
let headers_callback = () => {this.headers_callback()};
|
||||||
|
|
||||||
http_handle = create_handle(url, data_callback, finish_callback, headers_callback);
|
http_handle = create_request(url, data_callback, finish_callback, headers_callback);
|
||||||
_ftp_set_options(http_handle, url, 1);
|
_ftp_set_options(http_handle, url, 1);
|
||||||
start_request(http_handle);
|
start_request(http_handle);
|
||||||
});
|
});
|
||||||
|
|
141
client/javascript/http.js
Normal file
141
client/javascript/http.js
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
class HTTPSession extends CurlSession {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.set_connections(50, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
request_async(url, params, body) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let stream_controller;
|
||||||
|
let http_handle;
|
||||||
|
let response_obj;
|
||||||
|
let aborted = false;
|
||||||
|
|
||||||
|
//handle abort signals
|
||||||
|
if (params.signal instanceof AbortSignal) {
|
||||||
|
params.signal.addEventListener("abort", () => {
|
||||||
|
if (aborted) return;
|
||||||
|
aborted = true;
|
||||||
|
_cleanup_handle(http_handle);
|
||||||
|
if (!response_obj) {
|
||||||
|
reject(new DOMException("The operation was aborted."));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
stream_controller.error("The operation was aborted.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let stream = new ReadableStream({
|
||||||
|
start(controller) {
|
||||||
|
stream_controller = controller;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let data_callback = (new_data) => {
|
||||||
|
try {
|
||||||
|
stream_controller.enqueue(new_data);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
//the readable stream has been closed elsewhere, so cancel the request
|
||||||
|
if (e instanceof TypeError) {
|
||||||
|
_cleanup_handle(http_handle);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let headers_callback = () => {
|
||||||
|
let response_json = c_func_str(_http_get_info, [http_handle]);
|
||||||
|
response_obj = this.constructor.create_response(stream, JSON.parse(response_json));
|
||||||
|
resolve(response_obj);
|
||||||
|
}
|
||||||
|
let finish_callback = (error) => {
|
||||||
|
if (error != 0) {
|
||||||
|
error_msg(`Request "${url}" failed with error code ${error}: ${get_error_str(error)}`);
|
||||||
|
reject(`Request failed with error code ${error}: ${get_error_str(error)}`);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
stream_controller.close();
|
||||||
|
} //this will only fail if the stream is already errored or closed, which isn't a problem
|
||||||
|
catch {}
|
||||||
|
this.remove_request(http_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
let body_length = body ? body.length : 0;
|
||||||
|
let params_json = JSON.stringify(params);
|
||||||
|
|
||||||
|
http_handle = this.create_request(url, data_callback, finish_callback, headers_callback);
|
||||||
|
c_func(_http_set_options, [http_handle, params_json, body, body_length]);
|
||||||
|
this.start_request(http_handle);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetch(url, params={}) {
|
||||||
|
let body = await this.constructor.create_options(params);
|
||||||
|
return await this.request_async(url, params, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
static create_response(response_data, response_info) {
|
||||||
|
response_info.ok = response_info.status >= 200 && response_info.status < 300;
|
||||||
|
response_info.statusText = status_messages[response_info.status] || "";
|
||||||
|
if (response_info.status === 204 || response_info.status === 205) {
|
||||||
|
response_data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//construct base response object
|
||||||
|
let response_obj = new Response(response_data, response_info);
|
||||||
|
for (let key in response_info) {
|
||||||
|
if (key == "headers") continue;
|
||||||
|
Object.defineProperty(response_obj, key, {
|
||||||
|
writable: false,
|
||||||
|
value: response_info[key]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//create headers object
|
||||||
|
Object.defineProperty(response_obj, "headers", {
|
||||||
|
writable: false,
|
||||||
|
value: new Headers()
|
||||||
|
});
|
||||||
|
Object.defineProperty(response_obj, "raw_headers", {
|
||||||
|
writable: false,
|
||||||
|
value: response_info.headers
|
||||||
|
});
|
||||||
|
for (let [header_name, header_value] of response_info.headers) {
|
||||||
|
response_obj.headers.append(header_name, header_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response_obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async create_options(params) {
|
||||||
|
let body = null;
|
||||||
|
let request_obj = new Request("/", params);
|
||||||
|
let array_buffer = await request_obj.arrayBuffer();
|
||||||
|
if (array_buffer.byteLength > 0) {
|
||||||
|
body = new Uint8Array(array_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
let headers = params.headers || {};
|
||||||
|
if (params.headers instanceof Headers) {
|
||||||
|
for(let [key, value] of headers) {
|
||||||
|
headers[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params.headers = new HeadersDict(headers);
|
||||||
|
|
||||||
|
if (params.referrer) {
|
||||||
|
params.headers["Referer"] = params.referrer;
|
||||||
|
}
|
||||||
|
if (!params.headers["User-Agent"]) {
|
||||||
|
params.headers["User-Agent"] = navigator.userAgent;
|
||||||
|
}
|
||||||
|
if (body) {
|
||||||
|
params.headers["Content-Type"] = request_obj.headers.get("Content-Type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,11 +26,10 @@ const libcurl = (function() {
|
||||||
/* __extra_libraries__ */
|
/* __extra_libraries__ */
|
||||||
|
|
||||||
var websocket_url = null;
|
var websocket_url = null;
|
||||||
var event_loop = null;
|
|
||||||
var active_requests = 0;
|
|
||||||
var wasm_ready = false;
|
var wasm_ready = false;
|
||||||
var version_dict = null;
|
var version_dict = null;
|
||||||
var api = null;
|
var api = null;
|
||||||
|
var main_session = null;
|
||||||
const libcurl_version = "__library_version__";
|
const libcurl_version = "__library_version__";
|
||||||
const wisp_version = "__wisp_version__";
|
const wisp_version = "__wisp_version__";
|
||||||
|
|
||||||
|
@ -43,118 +42,6 @@ function check_loaded(check_websocket) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function create_handle(url, js_data_callback, js_end_callback, js_headers_callback) {
|
|
||||||
let end_callback_ptr;
|
|
||||||
let data_callback_ptr;
|
|
||||||
let headers_callback_ptr;
|
|
||||||
|
|
||||||
function end_callback(error) {
|
|
||||||
Module.removeFunction(end_callback_ptr);
|
|
||||||
Module.removeFunction(data_callback_ptr);
|
|
||||||
Module.removeFunction(headers_callback_ptr);
|
|
||||||
|
|
||||||
active_requests --;
|
|
||||||
js_end_callback(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
function data_callback(chunk_ptr, chunk_size) {
|
|
||||||
let data = Module.HEAPU8.subarray(chunk_ptr, chunk_ptr + chunk_size);
|
|
||||||
let chunk = new Uint8Array(data);
|
|
||||||
js_data_callback(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
function headers_callback() {
|
|
||||||
js_headers_callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
end_callback_ptr = Module.addFunction(end_callback, "vi");
|
|
||||||
headers_callback_ptr = Module.addFunction(headers_callback, "v");
|
|
||||||
data_callback_ptr = Module.addFunction(data_callback, "vii");
|
|
||||||
let http_handle = c_func(_create_handle, [url, data_callback_ptr, end_callback_ptr, headers_callback_ptr]);
|
|
||||||
|
|
||||||
return http_handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
function start_request(http_handle) {
|
|
||||||
_start_request(http_handle);
|
|
||||||
_tick_request();
|
|
||||||
active_requests ++;
|
|
||||||
|
|
||||||
if (!event_loop) {
|
|
||||||
event_loop = setInterval(() => {
|
|
||||||
if (_active_requests() || active_requests) {
|
|
||||||
_tick_request();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
clearInterval(event_loop);
|
|
||||||
event_loop = null;
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function create_response(response_data, response_info) {
|
|
||||||
response_info.ok = response_info.status >= 200 && response_info.status < 300;
|
|
||||||
response_info.statusText = status_messages[response_info.status] || "";
|
|
||||||
if (response_info.status === 204 || response_info.status === 205) {
|
|
||||||
response_data = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//construct base response object
|
|
||||||
let response_obj = new Response(response_data, response_info);
|
|
||||||
for (let key in response_info) {
|
|
||||||
if (key == "headers") continue;
|
|
||||||
Object.defineProperty(response_obj, key, {
|
|
||||||
writable: false,
|
|
||||||
value: response_info[key]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//create headers object
|
|
||||||
Object.defineProperty(response_obj, "headers", {
|
|
||||||
writable: false,
|
|
||||||
value: new Headers()
|
|
||||||
});
|
|
||||||
Object.defineProperty(response_obj, "raw_headers", {
|
|
||||||
writable: false,
|
|
||||||
value: response_info.headers
|
|
||||||
});
|
|
||||||
for (let [header_name, header_value] of response_info.headers) {
|
|
||||||
response_obj.headers.append(header_name, header_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response_obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function create_options(params) {
|
|
||||||
let body = null;
|
|
||||||
let request_obj = new Request("/", params);
|
|
||||||
let array_buffer = await request_obj.arrayBuffer();
|
|
||||||
if (array_buffer.byteLength > 0) {
|
|
||||||
body = new Uint8Array(array_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
let headers = params.headers || {};
|
|
||||||
if (params.headers instanceof Headers) {
|
|
||||||
for(let [key, value] of headers) {
|
|
||||||
headers[key] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
params.headers = new HeadersDict(headers);
|
|
||||||
|
|
||||||
if (params.referrer) {
|
|
||||||
params.headers["Referer"] = params.referrer;
|
|
||||||
}
|
|
||||||
if (!params.headers["User-Agent"]) {
|
|
||||||
params.headers["User-Agent"] = navigator.userAgent;
|
|
||||||
}
|
|
||||||
if (body) {
|
|
||||||
params.headers["Content-Type"] = request_obj.headers.get("Content-Type");
|
|
||||||
}
|
|
||||||
|
|
||||||
return body;
|
|
||||||
}
|
|
||||||
|
|
||||||
//wrap perform_request in a promise
|
//wrap perform_request in a promise
|
||||||
function perform_request_async(url, params, body) {
|
function perform_request_async(url, params, body) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -218,7 +105,7 @@ function perform_request_async(url, params, body) {
|
||||||
let body_length = body ? body.length : 0;
|
let body_length = body ? body.length : 0;
|
||||||
let params_json = JSON.stringify(params);
|
let params_json = JSON.stringify(params);
|
||||||
|
|
||||||
http_handle = create_handle(url, data_callback, finish_callback, headers_callback);
|
http_handle = create_request(url, data_callback, finish_callback, headers_callback);
|
||||||
c_func(_http_set_options, [http_handle, params_json, body, body_length]);
|
c_func(_http_set_options, [http_handle, params_json, body, body_length]);
|
||||||
start_request(http_handle);
|
start_request(http_handle);
|
||||||
});
|
});
|
||||||
|
@ -263,6 +150,10 @@ function main() {
|
||||||
let load_event = new Event("libcurl_load");
|
let load_event = new Event("libcurl_load");
|
||||||
document.dispatchEvent(load_event);
|
document.dispatchEvent(load_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main_session = new HTTPSession();
|
||||||
|
api.fetch = main_session.fetch.bind(main_session);
|
||||||
|
|
||||||
api.onload();
|
api.onload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,12 +165,8 @@ function load_wasm(url) {
|
||||||
|
|
||||||
Module.onRuntimeInitialized = main;
|
Module.onRuntimeInitialized = main;
|
||||||
api = {
|
api = {
|
||||||
fetch: libcurl_fetch,
|
|
||||||
set_websocket: set_websocket_url,
|
set_websocket: set_websocket_url,
|
||||||
load_wasm: load_wasm,
|
load_wasm: load_wasm,
|
||||||
WebSocket: FakeWebSocket,
|
|
||||||
CurlWebSocket: CurlWebSocket,
|
|
||||||
TLSSocket: TLSSocket,
|
|
||||||
get_cacert: get_cacert,
|
get_cacert: get_cacert,
|
||||||
get_error_string: get_error_str,
|
get_error_string: get_error_str,
|
||||||
|
|
||||||
|
@ -287,6 +174,11 @@ api = {
|
||||||
WispConnection: WispConnection,
|
WispConnection: WispConnection,
|
||||||
transport: "wisp",
|
transport: "wisp",
|
||||||
|
|
||||||
|
WebSocket: WebSocket,
|
||||||
|
CurlWebSocket: CurlWebSocket,
|
||||||
|
TLSSocket: TLSSocket,
|
||||||
|
fetch: () => {throw "not ready"},
|
||||||
|
|
||||||
get copyright() {return copyright_notice},
|
get copyright() {return copyright_notice},
|
||||||
get version() {return get_version()},
|
get version() {return get_version()},
|
||||||
get ready() {return wasm_ready},
|
get ready() {return wasm_ready},
|
||||||
|
|
98
client/javascript/session.js
Normal file
98
client/javascript/session.js
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
class CurlSession {
|
||||||
|
constructor(options={}) {
|
||||||
|
check_loaded(true);
|
||||||
|
|
||||||
|
this.options = options;
|
||||||
|
this.session_ptr = _session_create();
|
||||||
|
this.active_requests = 0;
|
||||||
|
this.event_loop = null;
|
||||||
|
this.requests_list = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_ready() {
|
||||||
|
if (!this.session_ptr) {
|
||||||
|
throw "session has been removed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_connections(connections_limit, cache_limit) {
|
||||||
|
this.assert_ready();
|
||||||
|
_session_set_options(this.session_ptr, connections_limit, cache_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
create_request(url, js_data_callback, js_end_callback, js_headers_callback) {
|
||||||
|
this.assert_ready();
|
||||||
|
let end_callback_ptr;
|
||||||
|
let data_callback_ptr;
|
||||||
|
let headers_callback_ptr;
|
||||||
|
|
||||||
|
let end_callback = (error) => {
|
||||||
|
Module.removeFunction(end_callback_ptr);
|
||||||
|
Module.removeFunction(data_callback_ptr);
|
||||||
|
Module.removeFunction(headers_callback_ptr);
|
||||||
|
|
||||||
|
this.active_requests--;
|
||||||
|
js_end_callback(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
let data_callback = (chunk_ptr, chunk_size) => {
|
||||||
|
let data = Module.HEAPU8.subarray(chunk_ptr, chunk_ptr + chunk_size);
|
||||||
|
let chunk = new Uint8Array(data);
|
||||||
|
js_data_callback(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
let headers_callback = () => {
|
||||||
|
js_headers_callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
end_callback_ptr = Module.addFunction(end_callback, "vi");
|
||||||
|
headers_callback_ptr = Module.addFunction(headers_callback, "v");
|
||||||
|
data_callback_ptr = Module.addFunction(data_callback, "vii");
|
||||||
|
let request_ptr = c_func(_create_request, [url, data_callback_ptr, end_callback_ptr, headers_callback_ptr]);
|
||||||
|
|
||||||
|
return request_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_request(request_ptr) {
|
||||||
|
this.assert_ready();
|
||||||
|
_session_remove_request(this.session_ptr, request_ptr);
|
||||||
|
|
||||||
|
let request_index = this.requests_list.indexOf(request_ptr);
|
||||||
|
if (request_index !== -1) {
|
||||||
|
this.requests_list.splice(request_index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start_request(request_ptr) {
|
||||||
|
this.assert_ready();
|
||||||
|
_session_add_request(this.session_ptr, request_ptr);
|
||||||
|
_session_perform(this.session_ptr);
|
||||||
|
|
||||||
|
this.active_requests++;
|
||||||
|
this.requests_list.push(request_ptr);
|
||||||
|
|
||||||
|
if (this.event_loop) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.event_loop = setInterval(() => {
|
||||||
|
let libcurl_active = _session_get_active(this.session_ptr);
|
||||||
|
if (libcurl_active || this.active_requests) {
|
||||||
|
_session_perform(this.session_ptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
clearInterval(this.event_loop);
|
||||||
|
this.event_loop = null;
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.assert_ready();
|
||||||
|
for (let request_ptr of this.requests_list) {
|
||||||
|
this.remove_request(request_ptr);
|
||||||
|
}
|
||||||
|
_session_cleanup(this.session_ptr);
|
||||||
|
this.session_ptr = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
//currently broken
|
//currently broken
|
||||||
|
|
||||||
class TLSSocket {
|
class TLSSocket extends CurlSession {
|
||||||
constructor(hostname, port, options={}) {
|
constructor(hostname, port, options={}) {
|
||||||
check_loaded(true);
|
super();
|
||||||
|
|
||||||
this.hostname = hostname;
|
this.hostname = hostname;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
|
@ -15,8 +15,9 @@ class TLSSocket {
|
||||||
this.onclose = () => {};
|
this.onclose = () => {};
|
||||||
|
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
this.event_loop = null;
|
this.recv_loop = null;
|
||||||
|
|
||||||
|
this.set_connections(1, 0);
|
||||||
this.connect();
|
this.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ class TLSSocket {
|
||||||
let finish_callback = (error) => {
|
let finish_callback = (error) => {
|
||||||
if (error === 0) {
|
if (error === 0) {
|
||||||
this.connected = true;
|
this.connected = true;
|
||||||
this.event_loop = setInterval(() => {
|
this.recv_loop = setInterval(() => {
|
||||||
let data = this.recv();
|
let data = this.recv();
|
||||||
if (data != null) this.onmessage(data);
|
if (data != null) this.onmessage(data);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
@ -40,9 +41,9 @@ class TLSSocket {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.http_handle = create_handle(this.url, data_callback, finish_callback, headers_callback);
|
this.http_handle = this.create_request(this.url, data_callback, finish_callback, headers_callback);
|
||||||
_tls_socket_set_options(this.http_handle, +this.options.verbose);
|
_tls_socket_set_options(this.http_handle, +this.options.verbose);
|
||||||
start_request(this.http_handle);
|
this.start_request(this.http_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
recv() {
|
recv() {
|
||||||
|
@ -80,10 +81,14 @@ class TLSSocket {
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup(error=false) {
|
cleanup(error=false) {
|
||||||
if (this.http_handle) _cleanup_handle(this.http_handle);
|
if (this.http_handle) {
|
||||||
|
this.remove_request(this.http_handle);
|
||||||
|
this.http_handle = null;
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
else return;
|
else return;
|
||||||
|
|
||||||
clearInterval(this.event_loop);
|
clearInterval(this.recv_loop);
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
class CurlWebSocket {
|
class CurlWebSocket extends CurlSession {
|
||||||
constructor(url, protocols=[], options={}) {
|
constructor(url, protocols=[], options={}) {
|
||||||
check_loaded(true);
|
|
||||||
if (!url.startsWith("wss://") && !url.startsWith("ws://")) {
|
if (!url.startsWith("wss://") && !url.startsWith("ws://")) {
|
||||||
throw new SyntaxError("invalid url");
|
throw new SyntaxError("invalid url");
|
||||||
}
|
}
|
||||||
|
super();
|
||||||
|
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.protocols = protocols;
|
this.protocols = protocols;
|
||||||
|
@ -15,9 +15,11 @@ class CurlWebSocket {
|
||||||
this.onclose = () => {};
|
this.onclose = () => {};
|
||||||
|
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
this.event_loop = null;
|
this.recv_loop = null;
|
||||||
|
this.http_handle = null;
|
||||||
this.recv_buffer = [];
|
this.recv_buffer = [];
|
||||||
|
|
||||||
|
this.set_connections(1, 0);
|
||||||
this.connect();
|
this.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +29,7 @@ class CurlWebSocket {
|
||||||
let finish_callback = (error) => {
|
let finish_callback = (error) => {
|
||||||
if (error === 0) {
|
if (error === 0) {
|
||||||
this.connected = true;
|
this.connected = true;
|
||||||
this.event_loop = setInterval(() => {
|
this.recv_loop = setInterval(() => {
|
||||||
let data = this.recv();
|
let data = this.recv();
|
||||||
if (data !== null) this.onmessage(data);
|
if (data !== null) this.onmessage(data);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
@ -47,10 +49,10 @@ class CurlWebSocket {
|
||||||
request_options._libcurl_verbose = 1;
|
request_options._libcurl_verbose = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.http_handle = create_handle(this.url, data_callback, finish_callback, headers_callback);
|
this.http_handle = this.create_request(this.url, data_callback, finish_callback, headers_callback);
|
||||||
c_func(_http_set_options, [this.http_handle, JSON.stringify(request_options), null, 0]);
|
c_func(_http_set_options, [this.http_handle, JSON.stringify(request_options), null, 0]);
|
||||||
_websocket_set_options(this.http_handle);
|
_websocket_set_options(this.http_handle);
|
||||||
start_request(this.http_handle);
|
this.start_request(this.http_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
recv() {
|
recv() {
|
||||||
|
@ -104,10 +106,14 @@ class CurlWebSocket {
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup(error=0) {
|
cleanup(error=0) {
|
||||||
if (this.http_handle) _cleanup_handle(this.http_handle);
|
if (this.http_handle) {
|
||||||
|
this.remove_handle(this.http_handle);
|
||||||
|
this.http_handle = null;
|
||||||
|
super.close();
|
||||||
|
}
|
||||||
else return;
|
else return;
|
||||||
|
|
||||||
clearInterval(this.event_loop);
|
clearInterval(this.recv_loop);
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|
|
@ -14,8 +14,6 @@
|
||||||
void finish_request(CURLMsg *curl_msg);
|
void finish_request(CURLMsg *curl_msg);
|
||||||
void forward_headers(struct RequestInfo *request_info);
|
void forward_headers(struct RequestInfo *request_info);
|
||||||
|
|
||||||
CURLM *multi_handle;
|
|
||||||
int request_active = 0;
|
|
||||||
struct curl_blob cacert_blob;
|
struct curl_blob cacert_blob;
|
||||||
|
|
||||||
size_t write_function(char *data, size_t size, size_t nmemb, struct RequestInfo *request_info) {
|
size_t write_function(char *data, size_t size, size_t nmemb, struct RequestInfo *request_info) {
|
||||||
|
@ -30,25 +28,7 @@ size_t write_function(char *data, size_t size, size_t nmemb, struct RequestInfo
|
||||||
return real_size;
|
return real_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
int active_requests() {
|
CURL* create_request(const char* url, DataCallback data_callback, EndCallback end_callback, HeadersCallback headers_callback) {
|
||||||
return request_active;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tick_request() {
|
|
||||||
CURLMcode mc;
|
|
||||||
struct CURLMsg *curl_msg;
|
|
||||||
request_active = 1;
|
|
||||||
|
|
||||||
mc = curl_multi_perform(multi_handle, &request_active);
|
|
||||||
|
|
||||||
int msgq = 0;
|
|
||||||
curl_msg = curl_multi_info_read(multi_handle, &msgq);
|
|
||||||
if (curl_msg && curl_msg->msg == CURLMSG_DONE) {
|
|
||||||
finish_request(curl_msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CURL* create_handle(const char* url, DataCallback data_callback, EndCallback end_callback, HeadersCallback headers_callback) {
|
|
||||||
CURL *http_handle = curl_easy_init();
|
CURL *http_handle = curl_easy_init();
|
||||||
|
|
||||||
//create request metadata struct
|
//create request metadata struct
|
||||||
|
@ -57,7 +37,6 @@ CURL* create_handle(const char* url, DataCallback data_callback, EndCallback end
|
||||||
request_info->curl_msg = NULL;
|
request_info->curl_msg = NULL;
|
||||||
request_info->headers_list = NULL;
|
request_info->headers_list = NULL;
|
||||||
request_info->headers_received = 0;
|
request_info->headers_received = 0;
|
||||||
request_info->prevent_cleanup = 0;
|
|
||||||
request_info->end_callback = end_callback;
|
request_info->end_callback = end_callback;
|
||||||
request_info->data_callback = data_callback;
|
request_info->data_callback = data_callback;
|
||||||
request_info->headers_callback = headers_callback;
|
request_info->headers_callback = headers_callback;
|
||||||
|
@ -73,10 +52,6 @@ CURL* create_handle(const char* url, DataCallback data_callback, EndCallback end
|
||||||
return http_handle;
|
return http_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void start_request(CURL* http_handle) {
|
|
||||||
curl_multi_add_handle(multi_handle, http_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void forward_headers(struct RequestInfo *request_info) {
|
void forward_headers(struct RequestInfo *request_info) {
|
||||||
request_info->headers_received = 1;
|
request_info->headers_received = 1;
|
||||||
(*request_info->headers_callback)();
|
(*request_info->headers_callback)();
|
||||||
|
@ -96,19 +71,6 @@ void finish_request(CURLMsg *curl_msg) {
|
||||||
curl_slist_free_all(request_info->headers_list);
|
curl_slist_free_all(request_info->headers_list);
|
||||||
}
|
}
|
||||||
(*request_info->end_callback)(error);
|
(*request_info->end_callback)(error);
|
||||||
if (request_info->prevent_cleanup) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
curl_multi_remove_handle(multi_handle, http_handle);
|
|
||||||
curl_easy_cleanup(http_handle);
|
|
||||||
free(request_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cleanup_handle(CURL* http_handle) {
|
|
||||||
struct RequestInfo *request_info = get_request_info(http_handle);
|
|
||||||
curl_multi_remove_handle(multi_handle, http_handle);
|
|
||||||
curl_easy_cleanup(http_handle);
|
|
||||||
free(request_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* get_cacert() {
|
unsigned char* get_cacert() {
|
||||||
|
@ -117,8 +79,6 @@ unsigned char* get_cacert() {
|
||||||
|
|
||||||
void init_curl() {
|
void init_curl() {
|
||||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||||
multi_handle = curl_multi_init();
|
|
||||||
|
|
||||||
cacert_blob.data = _cacert_pem;
|
cacert_blob.data = _cacert_pem;
|
||||||
cacert_blob.len = _cacert_pem_len;
|
cacert_blob.len = _cacert_pem_len;
|
||||||
cacert_blob.flags = CURL_BLOB_NOCOPY;
|
cacert_blob.flags = CURL_BLOB_NOCOPY;
|
3
client/libcurl/request.h
Normal file
3
client/libcurl/request.h
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#include "curl/multi.h"
|
||||||
|
|
||||||
|
void finish_request(CURLMsg *curl_msg);
|
52
client/libcurl/session.c
Normal file
52
client/libcurl/session.c
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "curl/multi.h"
|
||||||
|
#include "curl/curl.h"
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "request.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
struct SessionInfo* session_create() {
|
||||||
|
struct SessionInfo *session = malloc(sizeof(struct SessionInfo));
|
||||||
|
session->multi_handle = curl_multi_init();
|
||||||
|
session->request_active = 0;
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_perform(struct SessionInfo *session) {
|
||||||
|
CURLMcode mc;
|
||||||
|
session->request_active = 0;
|
||||||
|
mc = curl_multi_perform(session->multi_handle, &session->request_active);
|
||||||
|
|
||||||
|
int msgq = 0;
|
||||||
|
struct CURLMsg *curl_msg;
|
||||||
|
curl_msg = curl_multi_info_read(session->multi_handle, &msgq);
|
||||||
|
if (curl_msg && curl_msg->msg == CURLMSG_DONE) {
|
||||||
|
finish_request(curl_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_set_options(struct SessionInfo *session, int connections_limit, int cache_limit) {
|
||||||
|
curl_multi_setopt(session->multi_handle, CURLMOPT_MAX_TOTAL_CONNECTIONS, connections_limit);
|
||||||
|
curl_multi_setopt(session->multi_handle, CURLMOPT_MAXCONNECTS, cache_limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_add_request(struct SessionInfo *session, CURL* http_handle) {
|
||||||
|
curl_multi_add_handle(session->multi_handle, http_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
int session_get_active(struct SessionInfo *session) {
|
||||||
|
return session->request_active;
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_remove_request(struct SessionInfo *session, CURL* http_handle) {
|
||||||
|
struct RequestInfo *request_info = get_request_info(http_handle);
|
||||||
|
curl_multi_remove_handle(session->multi_handle, http_handle);
|
||||||
|
curl_easy_cleanup(http_handle);
|
||||||
|
free(request_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_cleanup(struct SessionInfo *session) {
|
||||||
|
curl_multi_cleanup(session->multi_handle);
|
||||||
|
}
|
|
@ -31,5 +31,4 @@ void tls_socket_set_options(CURL* http_handle, int verbose) {
|
||||||
curl_easy_setopt(http_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
curl_easy_setopt(http_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
|
||||||
curl_easy_setopt(http_handle, CURLOPT_SSL_ENABLE_ALPN, 0L);
|
curl_easy_setopt(http_handle, CURLOPT_SSL_ENABLE_ALPN, 0L);
|
||||||
curl_easy_setopt(http_handle, CURLOPT_VERBOSE, (long) verbose);
|
curl_easy_setopt(http_handle, CURLOPT_VERBOSE, (long) verbose);
|
||||||
request_info->prevent_cleanup = 1;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ typedef void(*HeadersCallback)();
|
||||||
|
|
||||||
struct RequestInfo {
|
struct RequestInfo {
|
||||||
CURL* http_handle;
|
CURL* http_handle;
|
||||||
int prevent_cleanup;
|
|
||||||
int headers_received;
|
int headers_received;
|
||||||
struct CURLMsg *curl_msg;
|
struct CURLMsg *curl_msg;
|
||||||
struct curl_slist* headers_list;
|
struct curl_slist* headers_list;
|
||||||
|
@ -23,3 +22,8 @@ struct WSResult {
|
||||||
int is_text;
|
int is_text;
|
||||||
char* buffer;
|
char* buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SessionInfo {
|
||||||
|
CURLM* multi_handle;
|
||||||
|
int request_active;
|
||||||
|
};
|
|
@ -40,7 +40,6 @@ void close_websocket(CURL* http_handle) {
|
||||||
void websocket_set_options(CURL* http_handle) {
|
void websocket_set_options(CURL* http_handle) {
|
||||||
struct RequestInfo *request_info = get_request_info(http_handle);
|
struct RequestInfo *request_info = get_request_info(http_handle);
|
||||||
curl_easy_setopt(http_handle, CURLOPT_CONNECT_ONLY, 2L);
|
curl_easy_setopt(http_handle, CURLOPT_CONNECT_ONLY, 2L);
|
||||||
request_info->prevent_cleanup = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_result_size (const struct WSResult* result) {
|
int get_result_size (const struct WSResult* result) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue