* Handles incoming POST messages. * * This should be called when a POST request is made to send a message to the server.
(req: IncomingMessage & { auth?: AuthInfo }, res: ServerResponse, parsedBody?: unknown)
| 135 | * This should be called when a POST request is made to send a message to the server. |
| 136 | */ |
| 137 | async handlePostMessage(req: IncomingMessage & { auth?: AuthInfo }, res: ServerResponse, parsedBody?: unknown): Promise<void> { |
| 138 | if (!this._sseResponse) { |
| 139 | const message = 'SSE connection not established'; |
| 140 | res.writeHead(500).end(message); |
| 141 | throw new Error(message); |
| 142 | } |
| 143 | |
| 144 | // Validate request headers for DNS rebinding protection |
| 145 | const validationError = this.validateRequestHeaders(req); |
| 146 | if (validationError) { |
| 147 | res.writeHead(403).end(validationError); |
| 148 | this.onerror?.(new Error(validationError)); |
| 149 | return; |
| 150 | } |
| 151 | |
| 152 | const authInfo: AuthInfo | undefined = req.auth; |
| 153 | |
| 154 | const host = req.headers.host; |
| 155 | const protocol = req.socket instanceof TLSSocket ? 'https' : 'http'; |
| 156 | const fullUrl = host && req.url ? new URL(req.url, `${protocol}://${host}`) : undefined; |
| 157 | |
| 158 | const requestInfo: RequestInfo = { |
| 159 | headers: req.headers, |
| 160 | url: fullUrl |
| 161 | }; |
| 162 | |
| 163 | let body: string | unknown; |
| 164 | try { |
| 165 | const ct = contentType.parse(req.headers['content-type'] ?? ''); |
| 166 | if (ct.type !== 'application/json') { |
| 167 | throw new Error(`Unsupported content-type: ${ct.type}`); |
| 168 | } |
| 169 | |
| 170 | body = |
| 171 | parsedBody ?? |
| 172 | (await getRawBody(req, { |
| 173 | limit: MAXIMUM_MESSAGE_SIZE, |
| 174 | encoding: ct.parameters.charset ?? 'utf-8' |
| 175 | })); |
| 176 | } catch (error) { |
| 177 | res.writeHead(400).end(String(error)); |
| 178 | this.onerror?.(error as Error); |
| 179 | return; |
| 180 | } |
| 181 | |
| 182 | try { |
| 183 | await this.handleMessage(typeof body === 'string' ? JSON.parse(body) : body, { requestInfo, authInfo }); |
| 184 | } catch { |
| 185 | res.writeHead(400).end(`Invalid message: ${body}`); |
| 186 | return; |
| 187 | } |
| 188 | |
| 189 | res.writeHead(202).end('Accepted'); |
| 190 | } |
| 191 | |
| 192 | /** |
| 193 | * Handle a client message, regardless of how it arrived. This can be used to inform the server of messages that arrive via a means different than HTTP POST. |