@gjsify/http2 0.49.0 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/client-session.js +1 -1
- package/lib/types/client-session.d.ts +17 -0
- package/package.json +10 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
import{__toCommonJS as e}from"./_virtual/_rolldown/runtime.js";import{constants as t,getDefaultSettings as n}from"./protocol.js";import{init_native_client_dispatcher as r,native_client_dispatcher_exports as i}from"./native-client-dispatcher.js";import a from"@girs/soup-3.0";import o from"@girs/gio-2.0";import s from"@girs/glib-2.0";import{EventEmitter as c}from"node:events";import{Duplex as l}from"node:stream";import{Buffer as u}from"node:buffer";import{readBytesAsync as d}from"@gjsify/utils";var Http2Session=class extends c{type=t.NGHTTP2_SESSION_CLIENT;alpnProtocol=void 0;encrypted=!1;_closed=!1;_destroyed=!1;_settings;constructor(){super(),this._settings=n()}get closed(){return this._closed}get destroyed(){return this._destroyed}get connecting(){return!1}get pendingSettingsAck(){return!1}get localSettings(){return{...this._settings}}get remoteSettings(){return n()}get originSet(){return new Set}settings(e,t){Object.assign(this._settings,e),t&&Promise.resolve().then(t)}goaway(e,n,r){this.emit(`goaway`,e??t.NGHTTP2_NO_ERROR),this.destroy()}ping(e,t){let n=e||new Uint8Array(8);return t&&Promise.resolve().then(()=>t(null,0,n)),!0}close(e){this._closed||(this._closed=!0,this.emit(`close`),e&&e())}destroy(e,t){this._destroyed||(this._destroyed=!0,this._closed=!0,e&&this.emit(`error`,e),t!==void 0&&this.emit(`goaway`,t),this.emit(`close`))}ref(){}unref(){}},ClientHttp2Stream=class extends l{_id=1;pending=!1;aborted=!1;bufferSize=0;endAfterHeaders=!1;_session;_requestHeaders;_requestChunks=[];_cancellable;_state=t.NGHTTP2_STREAM_STATE_OPEN;_responseHeaders={};_nativeStreamId=0;get id(){return this._id}get state(){return this._state}get rstCode(){return t.NGHTTP2_NO_ERROR}get session(){return this._session}get sentHeaders(){return this._requestHeaders}_setNativeStreamId(e){this._id=e,this._nativeStreamId=e,this._wireNativeBody()}constructor(e,t){super(),this._session=e,this._requestHeaders=t,this._cancellable=new o.Cancellable}_read(e){}_write(e,t,n){let r=u.isBuffer(e)?e:typeof e==`string`?u.from(e,t):u.from(e);this._nativeStreamId>0?this._session._getNativeClient().writeData(this._nativeStreamId,r,!1):this._requestChunks.push(r),n()}_final(e){let t=this._session._getNativeClient();if(t){try{if(this._nativeStreamId>0)t.writeData(this._nativeStreamId,u.alloc(0),!0);else{let n=u.concat(this._requestChunks),r=n.length===0,i=t.submitRequest(this._requestHeaders,r);if(i===0){e(Error(`Failed to submit HTTP/2 request stream`));return}this._id=i,this._nativeStreamId=i,n.length>0&&t.writeData(i,n,!0),this._wireNativeBody()}e()}catch(t){e(t instanceof Error?t:Error(String(t)))}return}this._sendRequest().then(()=>e()).catch(t=>e(t instanceof Error?t:Error(String(t))))}_wireNativeBody(){let e=this._session._getNativeClient();if(!e||this._nativeStreamId===0)return;let n=this._nativeStreamId;(async()=>{try{let r=Date.now()+3e4,i=null;for(;Date.now()<r&&(i=e.responseHeaders(n),!i);)await new Promise(e=>s.idle_add(s.PRIORITY_DEFAULT,()=>(e(),!1)));if(!i){this.destroy(Error(`Native HTTP/2 client: response headers timeout`));return}this._responseHeaders=i,this._state=t.NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL,this.emit(`response`,i,0);for await(let t of e.body(n))t.length>0&&this.push(t);this.push(null),this._state=t.NGHTTP2_STREAM_STATE_CLOSED}catch(e){this._state=t.NGHTTP2_STREAM_STATE_CLOSED,this.destroy(e instanceof Error?e:Error(String(e)))}})()}async _sendRequest(){let e=this._session._getSoupSession(),n=this._session._getAuthority(),r=this._requestHeaders[`:method`]||`GET`,i=this._requestHeaders[`:path`]||`/`,o=`${this._requestHeaders[`:scheme`]||(n.startsWith(`https`)?`https`:`http`)}://${this._requestHeaders[`:authority`]||n.replace(/^https?:\/\//,``)}${i}`,c;try{c=s.Uri.parse(o,s.UriFlags.NONE)}catch{throw Error(`Invalid HTTP/2 request URL: ${o}`)}let l=new a.Message({method:r,uri:c})
|
|
1
|
+
import{__toCommonJS as e}from"./_virtual/_rolldown/runtime.js";import{constants as t,getDefaultSettings as n}from"./protocol.js";import{init_native_client_dispatcher as r,native_client_dispatcher_exports as i}from"./native-client-dispatcher.js";import a from"@girs/soup-3.0";import o from"@girs/gio-2.0";import s from"@girs/glib-2.0";import{EventEmitter as c}from"node:events";import{Duplex as l}from"node:stream";import{Buffer as u}from"node:buffer";import{readBytesAsync as d}from"@gjsify/utils";var Http2Session=class extends c{type=t.NGHTTP2_SESSION_CLIENT;alpnProtocol=void 0;encrypted=!1;_closed=!1;_destroyed=!1;_settings;constructor(){super(),this._settings=n()}get closed(){return this._closed}get destroyed(){return this._destroyed}get connecting(){return!1}get pendingSettingsAck(){return!1}get localSettings(){return{...this._settings}}get remoteSettings(){return n()}get originSet(){return new Set}settings(e,t){Object.assign(this._settings,e),t&&Promise.resolve().then(t)}goaway(e,n,r){this.emit(`goaway`,e??t.NGHTTP2_NO_ERROR),this.destroy()}ping(e,t){let n=e||new Uint8Array(8);return t&&Promise.resolve().then(()=>t(null,0,n)),!0}close(e){this._closed||(this._closed=!0,this.emit(`close`),e&&e())}destroy(e,t){this._destroyed||(this._destroyed=!0,this._closed=!0,e&&this.emit(`error`,e),t!==void 0&&this.emit(`goaway`,t),this.emit(`close`))}ref(){}unref(){}},ClientHttp2Stream=class extends l{_id=1;pending=!1;aborted=!1;bufferSize=0;endAfterHeaders=!1;_session;_requestHeaders;_requestChunks=[];_cancellable;_state=t.NGHTTP2_STREAM_STATE_OPEN;_responseHeaders={};_nativeStreamId=0;get id(){return this._id}get state(){return this._state}get rstCode(){return t.NGHTTP2_NO_ERROR}get session(){return this._session}get sentHeaders(){return this._requestHeaders}_setNativeStreamId(e){this._id=e,this._nativeStreamId=e,this._wireNativeBody()}constructor(e,t){super(),this._session=e,this._requestHeaders=t,this._cancellable=new o.Cancellable}_read(e){}_write(e,t,n){let r=u.isBuffer(e)?e:typeof e==`string`?u.from(e,t):u.from(e);this._nativeStreamId>0?this._session._getNativeClient().writeData(this._nativeStreamId,r,!1):this._requestChunks.push(r),n()}_final(e){let t=this._session._getNativeClient();if(t){try{if(this._nativeStreamId>0)t.writeData(this._nativeStreamId,u.alloc(0),!0);else{let n=u.concat(this._requestChunks),r=n.length===0,i=t.submitRequest(this._requestHeaders,r);if(i===0){e(Error(`Failed to submit HTTP/2 request stream`));return}this._id=i,this._nativeStreamId=i,n.length>0&&t.writeData(i,n,!0),this._wireNativeBody()}e()}catch(t){e(t instanceof Error?t:Error(String(t)))}return}this._sendRequest().then(()=>e()).catch(t=>e(t instanceof Error?t:Error(String(t))))}_wireNativeBody(){let e=this._session._getNativeClient();if(!e||this._nativeStreamId===0)return;let n=this._nativeStreamId;(async()=>{try{let r=Date.now()+3e4,i=null;for(;Date.now()<r&&(i=e.responseHeaders(n),!i);)await new Promise(e=>s.idle_add(s.PRIORITY_DEFAULT,()=>(e(),!1)));if(!i){this.destroy(Error(`Native HTTP/2 client: response headers timeout`));return}this._responseHeaders=i,this._state=t.NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL,this.emit(`response`,i,0);for await(let t of e.body(n))t.length>0&&this.push(t);this.push(null),this._state=t.NGHTTP2_STREAM_STATE_CLOSED}catch(e){this._state=t.NGHTTP2_STREAM_STATE_CLOSED,this.destroy(e instanceof Error?e:Error(String(e)))}})()}async _sendRequest(){let e=this._session._getSoupSession(),n=this._session._getAuthority(),r=this._requestHeaders[`:method`]||`GET`,i=this._requestHeaders[`:path`]||`/`,o=`${this._requestHeaders[`:scheme`]||(n.startsWith(`https`)?`https`:`http`)}://${this._requestHeaders[`:authority`]||n.replace(/^https?:\/\//,``)}${i}`,c;try{c=s.Uri.parse(o,s.UriFlags.NONE)}catch{throw Error(`Invalid HTTP/2 request URL: ${o}`)}let l=new a.Message({method:r,uri:c});this._session._acceptsAnyCertificate()&&l.connect(`accept-certificate`,()=>!0);let f=l.get_request_headers();for(let[e,t]of Object.entries(this._requestHeaders))if(!e.startsWith(`:`))if(Array.isArray(t))for(let n of t)f.append(e,n);else f.replace(e,t);let p=u.concat(this._requestChunks);if(p.length>0){let e=this._requestHeaders[`content-type`]||`application/octet-stream`;l.set_request_body_from_bytes(e,new s.Bytes(p))}try{let n=await new Promise((t,n)=>{e.send_async(l,s.PRIORITY_DEFAULT,this._cancellable,(r,i)=>{try{t(e.send_finish(i))}catch(e){n(e)}})}),r=l.status_code,i=l.get_response_headers(),a={":status":String(r)};i.foreach((e,t)=>{let n=e.toLowerCase();if(n in a){let e=a[n];Array.isArray(e)?e.push(t):a[n]=[e,t]}else a[n]=t}),this._responseHeaders=a,this._state=t.NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL,this.emit(`response`,a,0);try{let e;for(;(e=await d(n,16384,s.PRIORITY_DEFAULT,this._cancellable))!==null;)e.length>0&&this.push(u.from(e))}catch{}this.push(null),this._state=t.NGHTTP2_STREAM_STATE_CLOSED}catch(e){this._state=t.NGHTTP2_STREAM_STATE_CLOSED,this._cancellable.is_cancelled()||this.destroy(e instanceof Error?e:Error(String(e)))}}close(e,n){this._cancellable.cancel(),this._state=t.NGHTTP2_STREAM_STATE_CLOSED,this.emit(`close`,e??t.NGHTTP2_NO_ERROR),n&&n()}priority(e){}sendTrailers(e){}setTimeout(e,t){return this}},ClientHttp2Session=class extends Http2Session{type=t.NGHTTP2_SESSION_CLIENT;_authority;_soupSession;_acceptAnyCertificate;_streams=new Set;_nativeClient=null;get nativeClient(){return this._nativeClient}constructor(e,t={}){super(),this._authority=e,this.encrypted=e.startsWith(`https:`),this._soupSession=new a.Session,this._acceptAnyCertificate=t.rejectUnauthorized===!1;let n=t.nativeDispatcher??`auto`;n===`force`&&this._setupNativeClient(e,n),Promise.resolve().then(()=>{if(!this.destroyed){let e=this;e.alpnProtocol=this.encrypted?`h2`:this._nativeClient?`h2c`:void 0,this.emit(`connect`,this,null)}})}_setupNativeClient(t,n){let{Http2NativeClientDispatcher:a}=(r(),e(i));if(!a.available()){if(n===`force`)throw Error(`@gjsify/http2-native prebuild not loadable — nativeDispatcher: "force" cannot proceed`);return}let[o,s]=t.replace(/^https?:\/\//,``).split(`:`),c=parseInt(s||(this.encrypted?`443`:`80`),10);this._nativeClient=new a({onPushPromise:e=>{let t=new ClientHttp2Stream(this,e.headers);t._setNativeStreamId(e.promisedStreamId),this._streams.add(t),this.emit(`stream`,t,e.headers,0)},onGoaway:(e,t)=>{this.emit(`goaway`,t,e)},onClose:()=>{}});try{this._nativeClient.connect(o||`localhost`,c)}catch(e){if(this._nativeClient=null,n===`force`)throw e}}_getSoupSession(){return this._soupSession}_getNativeClient(){return this._nativeClient}_getAuthority(){return this._authority}_acceptsAnyCertificate(){return this._acceptAnyCertificate}request(e,t){if(this.destroyed||this.closed)throw Error(`Session is closed`);let n={},r={};for(let[t,i]of Object.entries(e))t.startsWith(`:`)?n[t]=i:r[t]=i;n[`:method`]||=`GET`,n[`:scheme`]||=this.encrypted?`https`:`http`,n[`:authority`]||=this._authority.replace(/^https?:\/\//,``),n[`:path`]||=`/`;let i={...n,...r},a=new ClientHttp2Stream(this,i);return this._streams.add(a),a.once(`close`,()=>this._streams.delete(a)),t?.endStream&&a.end(),a}close(e){for(let e of this._streams)e.close();this._streams.clear(),super.close(e)}destroy(e,t){for(let e of this._streams)e.close();this._streams.clear(),super.destroy(e,t)}};export{ClientHttp2Session,ClientHttp2Stream,Http2Session};
|
|
@@ -114,6 +114,21 @@ export declare class ClientHttp2Session extends Http2Session {
|
|
|
114
114
|
readonly encrypted: boolean;
|
|
115
115
|
private _authority;
|
|
116
116
|
private _soupSession;
|
|
117
|
+
/**
|
|
118
|
+
* `rejectUnauthorized: false` — accept the peer certificate on every message
|
|
119
|
+
* this session sends.
|
|
120
|
+
*
|
|
121
|
+
* It is a per-MESSAGE decision because `accept-certificate` is a `Soup.Message`
|
|
122
|
+
* signal and libsoup 3 installs none of that name on `Soup.Session`. This used to
|
|
123
|
+
* connect it on the session, which THROWS — measured on libsoup 3:
|
|
124
|
+
* `No signal 'accept-certificate' on object 'SoupSession'`, and `signal_list_ids`
|
|
125
|
+
* on `SoupSession` answers `request-queued, request-unqueued` and nothing else.
|
|
126
|
+
* Nothing caught it because `@girs` 4.x let `connect` take any string, so the call
|
|
127
|
+
* type-checked and the option was simply dead. `@girs` 5.0.0 types `connect` on the
|
|
128
|
+
* object's own signal names and the line stopped compiling, which is what surfaced
|
|
129
|
+
* it. `@gjsify/fetch` already did it per message; this is the same idiom.
|
|
130
|
+
*/
|
|
131
|
+
private _acceptAnyCertificate;
|
|
117
132
|
private _streams;
|
|
118
133
|
private _nativeClient;
|
|
119
134
|
get nativeClient(): Http2NativeClientDispatcher | null;
|
|
@@ -125,6 +140,8 @@ export declare class ClientHttp2Session extends Http2Session {
|
|
|
125
140
|
_getNativeClient(): Http2NativeClientDispatcher | null;
|
|
126
141
|
/** @internal Used by ClientHttp2Stream to build the request URL */
|
|
127
142
|
_getAuthority(): string;
|
|
143
|
+
/** @internal Whether this session was opened with `rejectUnauthorized: false`. */
|
|
144
|
+
_acceptsAnyCertificate(): boolean;
|
|
128
145
|
request(headers: Record<string, string | string[]>, options?: ClientStreamOptions): ClientHttp2Stream;
|
|
129
146
|
close(callback?: () => void): void;
|
|
130
147
|
destroy(error?: Error, code?: number): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/http2",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0",
|
|
4
4
|
"description": "Node.js http2 module for Gjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -33,19 +33,19 @@
|
|
|
33
33
|
"http2"
|
|
34
34
|
],
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@gjsify/cli": "^0.
|
|
37
|
-
"@gjsify/unit": "^0.
|
|
36
|
+
"@gjsify/cli": "^0.50.0",
|
|
37
|
+
"@gjsify/unit": "^0.50.0",
|
|
38
38
|
"@types/node": "^25.9.2",
|
|
39
39
|
"typescript": "^6.0.3"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@girs/gio-2.0": "
|
|
43
|
-
"@girs/glib-2.0": "
|
|
44
|
-
"@girs/gobject-2.0": "
|
|
45
|
-
"@girs/soup-3.0": "
|
|
46
|
-
"@gjsify/events": "^0.
|
|
47
|
-
"@gjsify/http2-native": "^0.
|
|
48
|
-
"@gjsify/utils": "^0.
|
|
42
|
+
"@girs/gio-2.0": "5.0.0",
|
|
43
|
+
"@girs/glib-2.0": "5.0.0",
|
|
44
|
+
"@girs/gobject-2.0": "5.0.0",
|
|
45
|
+
"@girs/soup-3.0": "5.0.0",
|
|
46
|
+
"@gjsify/events": "^0.50.0",
|
|
47
|
+
"@gjsify/http2-native": "^0.50.0",
|
|
48
|
+
"@gjsify/utils": "^0.50.0"
|
|
49
49
|
},
|
|
50
50
|
"gjsify": {
|
|
51
51
|
"runtimes": {
|