aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-06-17 22:08:01 -0700
committerGravatar Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> 2023-06-17 22:08:01 -0700
commit503e7216fc2ef8cd14f6b3afb0301a39e81dcbc5 (patch)
tree47f2bc64026a89edefbea5157bce53b365e5aa29
parentb2af1984ed6db162468f3dd8c6d460420d4f4a2e (diff)
downloadbun-503e7216fc2ef8cd14f6b3afb0301a39e81dcbc5.tar.gz
bun-503e7216fc2ef8cd14f6b3afb0301a39e81dcbc5.tar.zst
bun-503e7216fc2ef8cd14f6b3afb0301a39e81dcbc5.zip
some fixes
-rw-r--r--src/js/builtins/EventSource.ts32
-rw-r--r--src/js/out/WebCoreJSBuiltins.cpp4
2 files changed, 25 insertions, 11 deletions
diff --git a/src/js/builtins/EventSource.ts b/src/js/builtins/EventSource.ts
index 64179bc0d..91364da04 100644
--- a/src/js/builtins/EventSource.ts
+++ b/src/js/builtins/EventSource.ts
@@ -25,6 +25,12 @@
export function getEventSource() {
type Socket = Awaited<ReturnType<typeof Bun.connect<EventSource>>>;
+ class ConnectionError extends Error {}
+ Object.defineProperty(ConnectionError.prototype, "name", { value: "ConnectionError" });
+
+ class ProtocolError extends Error {}
+ Object.defineProperty(ProtocolError.prototype, "name", { value: "ProtocolError" });
+
class EventSource extends EventTarget {
#url;
#state;
@@ -48,7 +54,7 @@ export function getEventSource() {
static #SendRequest(socket: Socket, url: URL) {
const self = socket.data;
const last_event_header = self.#lastEventID ? `Last-Event-ID: ${self.#lastEventID}\r\n` : "";
- const request = `GET ${url.pathname}${url.search} HTTP/1.1\r\nHost: bun\r\nContent-type: text/event-stream\r\nContent-length: 0\r\n${last_event_header}\r\n`;
+ const request = `GET ${url.pathname}${url.search} HTTP/1.1\r\nHost: ${url.host}\r\nConnection: Close\r\nContent-Type: text/event-stream\r\nContent-Length: 0\r\n${last_event_header}\r\n`;
const sended = socket.write(request);
if (sended !== request.length) {
self.#send_buffer = request.substring(sended);
@@ -176,6 +182,7 @@ export function getEventSource() {
static #Handlers = {
open(socket: Socket) {
const self = socket.data;
+ socket.timeout(999_999_999);
self.#socket = socket;
if (!self.#is_tls) {
EventSource.#SendRequest(socket, self.#url);
@@ -196,6 +203,7 @@ export function getEventSource() {
switch (self.#state) {
case 0: {
let text = buffer.toString();
+
const headers_idx = text.indexOf("\r\n\r\n");
if (headers_idx === -1) {
// wait headers
@@ -213,14 +221,18 @@ export function getEventSource() {
if (status_idx === -1) {
self.#state = 2;
- self.dispatchEvent(new ErrorEvent("error", { error: new Error("Invalid HTTP request") }));
+ self.dispatchEvent(new ErrorEvent("error", { error: new ProtocolError("Invalid HTTP request") }));
socket.end();
return;
}
const status = headers.substring(0, status_idx);
if (status !== "HTTP/1.1 200 OK") {
self.#state = 2;
- self.dispatchEvent(new ErrorEvent("error", { error: new Error(status) }));
+ self.dispatchEvent(
+ new ErrorEvent("error", {
+ error: new ProtocolError("Unexpected status line\n" + JSON.stringify(headers)),
+ }),
+ );
socket.end();
return;
}
@@ -237,8 +249,8 @@ export function getEventSource() {
self.#state = 2;
self.dispatchEvent(
new ErrorEvent("error", {
- error: new Error(
- `EventSource's response has no MIME type and "text/event-stream" is required. Aborting the connection.`,
+ error: new ProtocolError(
+ `EventSource HTTP response must have \"Content-Type\" header set to "text/event-stream". Aborting the connection.`,
),
}),
);
@@ -265,8 +277,8 @@ export function getEventSource() {
self.#state = 2;
self.dispatchEvent(
new ErrorEvent("error", {
- error: new Error(
- `EventSource's response has a MIME type that is not "text/event-stream". Aborting the connection.`,
+ error: new ProtocolError(
+ `EventSource HTTP response must have \"Content-Type\" header set to "text/event-stream". Aborting the connection.`,
),
}),
);
@@ -297,7 +309,9 @@ export function getEventSource() {
if (header.substring(header_name_idx + 1).trim() !== "chunked") {
self.dispatchEvent(
new ErrorEvent("error", {
- error: new Error(`EventSource's Transfer-Encoding is invalid. Aborting the connection.`),
+ error: new ProtocolError(
+ `EventSource's Transfer-Encoding is invalid. Aborting the connection.`,
+ ),
}),
);
socket.end();
@@ -418,7 +432,7 @@ export function getEventSource() {
}
: false,
}).catch(err => {
- super.dispatchEvent(new ErrorEvent("error", { error: err }));
+ this.dispatchEvent(new ErrorEvent("error", { error: err }));
if (this.#reconnect) {
if (this.#reconnection_timer) {
this.#reconnection_timer.unref?.();
diff --git a/src/js/out/WebCoreJSBuiltins.cpp b/src/js/out/WebCoreJSBuiltins.cpp
index 55238274b..a8c351fb4 100644
--- a/src/js/out/WebCoreJSBuiltins.cpp
+++ b/src/js/out/WebCoreJSBuiltins.cpp
@@ -2916,9 +2916,9 @@ WEBCORE_FOREACH_WRITABLESTREAMDEFAULTCONTROLLER_BUILTIN_CODE(DEFINE_BUILTIN_GENE
const JSC::ConstructAbility s_eventSourceGetEventSourceCodeConstructAbility = JSC::ConstructAbility::CannotConstruct;
const JSC::ConstructorKind s_eventSourceGetEventSourceCodeConstructorKind = JSC::ConstructorKind::None;
const JSC::ImplementationVisibility s_eventSourceGetEventSourceCodeImplementationVisibility = JSC::ImplementationVisibility::Public;
-const int s_eventSourceGetEventSourceCodeLength = 5476;
+const int s_eventSourceGetEventSourceCodeLength = 5813;
static const JSC::Intrinsic s_eventSourceGetEventSourceCodeIntrinsic = JSC::NoIntrinsic;
-const char* const s_eventSourceGetEventSourceCode = "(function (){\"use strict\";class j extends EventTarget{#$;#j;#w;#A;#B;#F=!1;#G=null;#J=\"\";#K=\"\";#L=\"\";#M=!0;#O=0;#Q=0;#U=0;#V=null;static#W(w){w.#H()}static#X(w,A){const B=w.data,F=B.#L\?`Last-Event-ID: ${B.#L}\\r\\n`:\"\",G=`GET ${A.pathname}${A.search} HTTP/1.1\\r\\nHost: bun\\r\\nContent-type: text/event-stream\\r\\nContent-length: 0\\r\\n${F}\\r\\n`,J=w.write(G);if(J!==G.length)B.#K=G.substring(J)}static#Y(w,A,B){for(;;){if(B>=A.length)return;let F=-1,G=A.indexOf(\"\\r\\n\",B);const J=G+2;if(G>0)if(w.#O===0){const Q=parseInt(A.substring(B,G),16);if(Q===0){w.#j=2,w.#G\?.end();return}F=J+Q}else F=A.length;else{if(w.#J.length===0){w.#J+=A.substring(B);return}F=A.length}let K=A.substring(J,F);B=F+2;let L=0,M=K.indexOf(\"\\n\\n\");if(M==-1){w.#J+=A.substring(J);return}if(w.#J.length)w.#J+=K,K=w.#J,w.#J=\"\";let O=!0;while(O){const Q=K.substring(L,M);let U,V=\"\",W,X=0,Y=-1;for(;;){let z=Q.indexOf(\"\\n\",X);if(z===-1){if(X>=Q.length)break;z=Q.length}const H=Q.substring(X,z);if(H.startsWith(\"data:\"))if(V.length)V+=`\\n${H.substring(5).trim()}`;else V=H.substring(5).trim();else if(H.startsWith(\"event:\"))U=H.substring(6).trim();else if(H.startsWith(\"id:\"))W=H.substring(3).trim();else if(H.startsWith(\"retry:\")){if(Y=parseInt(H.substring(6).trim(),10),@isNaN(Y))Y=-1}X=z+1}if(w.#L=W||\"\",Y>=0)w.#U=Y;if(V||W||U)w.dispatchEvent(new MessageEvent(U||\"message\",{data:V||\"\",origin:w.#$.origin,source:w,lastEventId:W}));if(K.length===M+2){O=!1;break}const Z=K.indexOf(\"\\n\\n\",M+1);if(Z===-1)break;L=M,M=Z}}}static#Z={open(w){const A=w.data;if(A.#G=w,!A.#F)j.#X(w,A.#$)},handshake(w,A,B){const F=w.data;if(A)j.#X(w,F.#$);else F.#j=2,F.dispatchEvent(new ErrorEvent(\"error\",{error:B})),w.end()},data(w,A){const B=w.data;switch(B.#j){case 0:{let F=A.toString();const G=F.indexOf(\"\\r\\n\\r\\n\");if(G===-1){B.#J+=F;return}if(B.#J.length)B.#J+=F,F=B.#J,B.#J=\"\";const J=F.substring(0,G),K=J.indexOf(\"\\r\\n\");if(K===-1){B.#j=2,B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(\"Invalid HTTP request\")})),w.end();return}const L=J.substring(0,K);if(L!==\"HTTP/1.1 200 OK\"){B.#j=2,B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(L)})),w.end();return}let M=K+1,O=!1,Q=-1;for(;;){let V=J.indexOf(\"\\r\\n\",M);if(V===-1){if(M>=J.length){if(!O)B.#j=2,B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's response has no MIME type and \"text/event-stream\" is required. Aborting the connection.`)})),w.end();return}V=J.length}const W=J.substring(M+1,V),X=W.indexOf(\":\"),Y=W.substring(0,X),Z=Y.localeCompare(\"content-type\",@undefined,{sensitivity:\"accent\"})===0;if(M=V+1,Z)if(W.endsWith(\" text/event-stream\"))O=!0;else{B.#j=2,B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's response has a MIME type that is not \"text/event-stream\". Aborting the connection.`)})),w.end();return}else if(Y.localeCompare(\"content-length\",@undefined,{sensitivity:\"accent\"})===0){if(Q=parseInt(W.substring(X+1).trim(),10),@isNaN(Q)||Q<=0){B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's Content-Length is invalid. Aborting the connection.`)})),w.end();return}if(O)break}else if(Y.localeCompare(\"transfer-encoding\",@undefined,{sensitivity:\"accent\"})===0){if(W.substring(X+1).trim()!==\"chunked\"){B.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's Transfer-Encoding is invalid. Aborting the connection.`)})),w.end();return}if(Q=0,O)break}}B.#O=Q,B.#j=1,B.dispatchEvent(new Event(\"open\"));const U=F.substring(G+4);if(j.#Y(B,U,0),B.#O>0){if(B.#Q+=U.length,B.#Q>=B.#O)B.#j=2,w.end()}return}case 1:if(j.#Y(B,A.toString(),2),B.#O>0){if(B.#Q+=A.byteLength,B.#Q>=B.#O)B.#j=2,w.end()}return;default:break}},drain(w){const A=w.data;if(A.#j===0){const B=A.#J;if(B.length){const F=w.write(B);if(F!==B.length)w.data.#K=B.substring(F);else w.data.#K=\"\"}}},close:j.#z,end(w){j.#z(w).dispatchEvent(new ErrorEvent(\"error\",{error:new Error(\"Connection closed by server\")}))},timeout(w){j.#z(w).dispatchEvent(new ErrorEvent(\"error\",{error:new Error(\"Timeout\")}))},binaryType:\"buffer\"};static#z(w){const A=w.data;if(A.#G=null,A.#Q=0,A.#j=2,A.#M){if(A.#V)clearTimeout(A.#V);A.#V=setTimeout(j.#W,A.#U,A)}return A}constructor(w,A=@undefined){super();const B=new URL(w);this.#F=B.protocol===\"https:\",this.#$=B,this.#j=2,process.nextTick(j.#W,this)}ref(){this.#V\?.ref(),this.#G\?.ref()}unref(){this.#V\?.unref(),this.#G\?.unref()}#H(){if(this.#j!==2)return;const w=this.#$,A=this.#F;this.#j=0,@Bun.connect({data:this,socket:j.#Z,hostname:w.hostname,port:parseInt(w.port||(A\?\"443\":\"80\"),10),tls:A\?{requestCert:!0,rejectUnauthorized:!1}:!1}).catch((B)=>{if(this.dispatchEvent(new ErrorEvent(\"error\",{error:B})),this.#M){if(this.#V)this.#V.unref\?.();this.#V=setTimeout(j.#W,1000,this)}})}get url(){return this.#$.href}get readyState(){return this.#j}close(){this.#M=!1,this.#j=2,this.#G\?.unref(),this.#G\?.end()}get onopen(){return this.#B}get onerror(){return this.#w}get onmessage(){return this.#A}set onopen(w){if(this.#B)super.removeEventListener(\"close\",this.#B);super.addEventListener(\"open\",w),this.#B=w}set onerror(w){if(this.#w)super.removeEventListener(\"error\",this.#w);super.addEventListener(\"error\",w),this.#w=w}set onmessage(w){if(this.#A)super.removeEventListener(\"message\",this.#A);super.addEventListener(\"message\",w),this.#A=w}}return Object.defineProperty(j.prototype,\"CONNECTING\",{enumerable:!0,value:0}),Object.defineProperty(j.prototype,\"OPEN\",{enumerable:!0,value:1}),Object.defineProperty(j.prototype,\"CLOSED\",{enumerable:!0,value:2}),j[Symbol.for(\"CommonJS\")]=0,j})\n";
+const char* const s_eventSourceGetEventSourceCode = "(function (){\"use strict\";class w extends Error{constructor(){super(...arguments)}}Object.defineProperty(w.prototype,\"name\",{value:\"ConnectionError\"});class O extends Error{constructor(){super(...arguments)}}Object.defineProperty(O.prototype,\"name\",{value:\"ProtocolError\"});class j extends EventTarget{#$;#w;#O;#j;#A;#B=!1;#F=null;#G=\"\";#J=\"\";#K=\"\";#L=!0;#M=0;#Q=0;#U=0;#V=null;static#W(A){A.#H()}static#X(A,B){const F=A.data,G=F.#K\?`Last-Event-ID: ${F.#K}\\r\\n`:\"\",J=`GET ${B.pathname}${B.search} HTTP/1.1\\r\\nHost: ${B.host}\\r\\nConnection: Close\\r\\nContent-Type: text/event-stream\\r\\nContent-Length: 0\\r\\n${G}\\r\\n`,K=A.write(J);if(K!==J.length)F.#J=J.substring(K)}static#Y(A,B,F){for(;;){if(F>=B.length)return;let G=-1,J=B.indexOf(\"\\r\\n\",F);const K=J+2;if(J>0)if(A.#M===0){const V=parseInt(B.substring(F,J),16);if(V===0){A.#w=2,A.#F\?.end();return}G=K+V}else G=B.length;else{if(A.#G.length===0){A.#G+=B.substring(F);return}G=B.length}let L=B.substring(K,G);F=G+2;let M=0,Q=L.indexOf(\"\\n\\n\");if(Q==-1){A.#G+=B.substring(K);return}if(A.#G.length)A.#G+=L,L=A.#G,A.#G=\"\";let U=!0;while(U){const V=L.substring(M,Q);let W,X=\"\",Y,Z=0,z=-1;for(;;){let T=V.indexOf(\"\\n\",Z);if(T===-1){if(Z>=V.length)break;T=V.length}const N=V.substring(Z,T);if(N.startsWith(\"data:\"))if(X.length)X+=`\\n${N.substring(5).trim()}`;else X=N.substring(5).trim();else if(N.startsWith(\"event:\"))W=N.substring(6).trim();else if(N.startsWith(\"id:\"))Y=N.substring(3).trim();else if(N.startsWith(\"retry:\")){if(z=parseInt(N.substring(6).trim(),10),@isNaN(z))z=-1}Z=T+1}if(A.#K=Y||\"\",z>=0)A.#U=z;if(X||Y||W)A.dispatchEvent(new MessageEvent(W||\"message\",{data:X||\"\",origin:A.#$.origin,source:A,lastEventId:Y}));if(L.length===Q+2){U=!1;break}const H=L.indexOf(\"\\n\\n\",Q+1);if(H===-1)break;M=Q,Q=H}}}static#Z={open(A){const B=A.data;if(A.timeout(999999999),B.#F=A,!B.#B)j.#X(A,B.#$)},handshake(A,B,F){const G=A.data;if(B)j.#X(A,G.#$);else G.#w=2,G.dispatchEvent(new ErrorEvent(\"error\",{error:F})),A.end()},data(A,B){const F=A.data;switch(F.#w){case 0:{let G=B.toString();const J=G.indexOf(\"\\r\\n\\r\\n\");if(J===-1){F.#G+=G;return}if(F.#G.length)F.#G+=G,G=F.#G,F.#G=\"\";const K=G.substring(0,J),L=K.indexOf(\"\\r\\n\");if(L===-1){F.#w=2,F.dispatchEvent(new ErrorEvent(\"error\",{error:new O(\"Invalid HTTP request\")})),A.end();return}if(K.substring(0,L)!==\"HTTP/1.1 200 OK\"){F.#w=2,F.dispatchEvent(new ErrorEvent(\"error\",{error:new O(\"Unexpected status line:\\n\"+JSON.stringify(K))})),A.end();return}let Q=L+1,U=!1,V=-1;for(;;){let X=K.indexOf(\"\\r\\n\",Q);if(X===-1){if(Q>=K.length){if(!U)F.#w=2,F.dispatchEvent(new ErrorEvent(\"error\",{error:new O(`EventSource HTTP response must have \\\"Content-Type\\\" header set to \"text/event-stream\". Aborting the connection.`)})),A.end();return}X=K.length}const Y=K.substring(Q+1,X),Z=Y.indexOf(\":\"),z=Y.substring(0,Z),H=z.localeCompare(\"content-type\",@undefined,{sensitivity:\"accent\"})===0;if(Q=X+1,H)if(Y.endsWith(\" text/event-stream\"))U=!0;else{F.#w=2,F.dispatchEvent(new ErrorEvent(\"error\",{error:new O(`EventSource HTTP response must have \\\"Content-Type\\\" header set to \"text/event-stream\". Aborting the connection.`)})),A.end();return}else if(z.localeCompare(\"content-length\",@undefined,{sensitivity:\"accent\"})===0){if(V=parseInt(Y.substring(Z+1).trim(),10),@isNaN(V)||V<=0){F.dispatchEvent(new ErrorEvent(\"error\",{error:new Error(`EventSource's Content-Length is invalid. Aborting the connection.`)})),A.end();return}if(U)break}else if(z.localeCompare(\"transfer-encoding\",@undefined,{sensitivity:\"accent\"})===0){if(Y.substring(Z+1).trim()!==\"chunked\"){F.dispatchEvent(new ErrorEvent(\"error\",{error:new O(`EventSource's Transfer-Encoding is invalid. Aborting the connection.`)})),A.end();return}if(V=0,U)break}}F.#M=V,F.#w=1,F.dispatchEvent(new Event(\"open\"));const W=G.substring(J+4);if(j.#Y(F,W,0),F.#M>0){if(F.#Q+=W.length,F.#Q>=F.#M)F.#w=2,A.end()}return}case 1:if(j.#Y(F,B.toString(),2),F.#M>0){if(F.#Q+=B.byteLength,F.#Q>=F.#M)F.#w=2,A.end()}return;default:break}},drain(A){const B=A.data;if(B.#w===0){const F=B.#G;if(F.length){const G=A.write(F);if(G!==F.length)A.data.#J=F.substring(G);else A.data.#J=\"\"}}},close:j.#z,end(A){j.#z(A).dispatchEvent(new ErrorEvent(\"error\",{error:new Error(\"Connection closed by server\")}))},timeout(A){j.#z(A).dispatchEvent(new ErrorEvent(\"error\",{error:new Error(\"Timeout\")}))},binaryType:\"buffer\"};static#z(A){const B=A.data;if(B.#F=null,B.#Q=0,B.#w=2,B.#L){if(B.#V)clearTimeout(B.#V);B.#V=setTimeout(j.#W,B.#U,B)}return B}constructor(A,B=@undefined){super();const F=new URL(A);this.#B=F.protocol===\"https:\",this.#$=F,this.#w=2,process.nextTick(j.#W,this)}ref(){this.#V\?.ref(),this.#F\?.ref()}unref(){this.#V\?.unref(),this.#F\?.unref()}#H(){if(this.#w!==2)return;const A=this.#$,B=this.#B;this.#w=0,@Bun.connect({data:this,socket:j.#Z,hostname:A.hostname,port:parseInt(A.port||(B\?\"443\":\"80\"),10),tls:B\?{requestCert:!0,rejectUnauthorized:!1}:!1}).catch((F)=>{if(this.dispatchEvent(new ErrorEvent(\"error\",{error:F})),this.#L){if(this.#V)this.#V.unref\?.();this.#V=setTimeout(j.#W,1000,this)}})}get url(){return this.#$.href}get readyState(){return this.#w}close(){this.#L=!1,this.#w=2,this.#F\?.unref(),this.#F\?.end()}get onopen(){return this.#A}get onerror(){return this.#O}get onmessage(){return this.#j}set onopen(A){if(this.#A)super.removeEventListener(\"close\",this.#A);super.addEventListener(\"open\",A),this.#A=A}set onerror(A){if(this.#O)super.removeEventListener(\"error\",this.#O);super.addEventListener(\"error\",A),this.#O=A}set onmessage(A){if(this.#j)super.removeEventListener(\"message\",this.#j);super.addEventListener(\"message\",A),this.#j=A}}return Object.defineProperty(j.prototype,\"CONNECTING\",{enumerable:!0,value:0}),Object.defineProperty(j.prototype,\"OPEN\",{enumerable:!0,value:1}),Object.defineProperty(j.prototype,\"CLOSED\",{enumerable:!0,value:2}),j[Symbol.for(\"CommonJS\")]=0,j})\n";
#define DEFINE_BUILTIN_GENERATOR(codeName, functionName, overriddenName, argumentCount) \
JSC::FunctionExecutable* codeName##Generator(JSC::VM& vm) \