data()

in src/js/builtins/EventSource.ts [194:342]


      data(socket: Socket, buffer: Buffer) {
        const self = socket.data;
        switch (self.#state) {
          case 0: {
            let text = buffer.toString();
            const headers_idx = text.indexOf("\r\n\r\n");
            if (headers_idx === -1) {
              // wait headers
              self.#data_buffer += text;
              return;
            }

            if (self.#data_buffer.length) {
              self.#data_buffer += text;
              text = self.#data_buffer;
              self.#data_buffer = "";
            }
            const headers = text.substring(0, headers_idx);
            const status_idx = headers.indexOf("\r\n");

            if (status_idx === -1) {
              self.#state = 2;
              self.dispatchEvent(new ErrorEvent("error", { error: new Error("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) }));
              socket.end();
              return;
            }

            let start_idx = status_idx + 1;
            let mime_type_ok = false;
            let content_length = -1;
            for (;;) {
              let header_idx = headers.indexOf("\r\n", start_idx);
              // No text/event-stream mime type
              if (header_idx === -1) {
                if (start_idx >= headers.length) {
                  if (!mime_type_ok) {
                    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.`,
                        ),
                      }),
                    );
                    socket.end();
                  }
                  return;
                }

                header_idx = headers.length;
              }

              const header = headers.substring(start_idx + 1, header_idx);
              const header_name_idx = header.indexOf(":");
              const header_name = header.substring(0, header_name_idx);
              const is_content_type =
                header_name.localeCompare("content-type", undefined, { sensitivity: "accent" }) === 0;
              start_idx = header_idx + 1;

              if (is_content_type) {
                if (header.endsWith(" text/event-stream")) {
                  mime_type_ok = true;
                } else {
                  // wrong mime type
                  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.`,
                      ),
                    }),
                  );
                  socket.end();
                  return;
                }
              } else {
                const is_content_length =
                  header_name.localeCompare("content-length", undefined, { sensitivity: "accent" }) === 0;
                if (is_content_length) {
                  content_length = parseInt(header.substring(header_name_idx + 1).trim(), 10);
                  if (content_length !== content_length || content_length <= 0) {
                    self.dispatchEvent(
                      new ErrorEvent("error", {
                        error: new Error(`EventSource's Content-Length is invalid. Aborting the connection.`),
                      }),
                    );
                    socket.end();
                    return;
                  }
                  if (mime_type_ok) {
                    break;
                  }
                } else {
                  const is_transfer_encoding =
                    header_name.localeCompare("transfer-encoding", undefined, { sensitivity: "accent" }) === 0;
                  if (is_transfer_encoding) {
                    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.`),
                        }),
                      );
                      socket.end();
                      return;
                    }
                    content_length = 0;
                    if (mime_type_ok) {
                      break;
                    }
                  }
                }
              }
            }

            self.#content_length = content_length;
            self.#state = 1;
            self.dispatchEvent(new Event("open"));
            const chunks = text.substring(headers_idx + 4);
            EventSource.#ProcessChunk(self, chunks, 0);
            if (self.#content_length > 0) {
              self.#received_length += chunks.length;
              if (self.#received_length >= self.#content_length) {
                self.#state = 2;
                socket.end();
              }
            }
            return;
          }
          case 1:
            EventSource.#ProcessChunk(self, buffer.toString(), 2);
            if (self.#content_length > 0) {
              self.#received_length += buffer.byteLength;
              if (self.#received_length >= self.#content_length) {
                self.#state = 2;
                socket.end();
              }
            }
            return;
          default:
            break;
        }
      },