parseResponse static method
Implementation
static bool parseResponse(String resp, String key) {
response += resp;
final bodyOffset = response.indexOf('\n\n');
// if we don't have a double newline yet we need to go back for more.
if (bodyOffset < 0) {
return true;
}
final lines = '${response.characters.getRange(0, bodyOffset)}'.split('\n');
if (lines.isEmpty) {
throw MqttNoConnectionException(
'MqttServerWs2Connection::server returned invalid response',
);
}
// split apart the status line
final status = lines.first.split(' ');
if (status.length < MqttServerWs2Connection.statusLines) {
throw MqttNoConnectionException(
'MqttServerWs2Connection::server returned malformed status line',
);
}
// make a map of the headers
final headers = <String, String>{};
lines.removeAt(0);
for (final l in lines) {
final space = l.indexOf(' ');
if (space < 0) {
throw MqttNoConnectionException(
'MqttServerWs2Connection::server returned malformed header line',
);
}
headers['${l.characters.getRange(0, space - 1)}'.toLowerCase()] =
'${l.characters.getRange(space + 1)}';
}
var body = '';
// if we have a Content-Length key we can't stop till we read the body.
if (headers.containsKey('content-length')) {
final bodyLength = int.parse(headers['content-length']!);
if (response.length <
bodyOffset + bodyLength + MqttServerWs2Connection.bodyOffset) {
return true;
}
body =
'${response.characters.getRange(bodyOffset, bodyOffset + bodyLength + MqttServerWs2Connection.bodyOffset)}';
}
// if we make it to here we have read all we are going to read.
// now lets see if we like what we found.
if (status[1] != '101') {
throw MqttNoConnectionException(
'MqttServerWs2Connection::server refused to upgrade, response = '
'${status[1]} - ${status[2]} - $body',
);
}
if (!headers.containsKey('connection') ||
headers['connection']!.toLowerCase() != 'upgrade') {
throw MqttNoConnectionException(
'MqttServerWs2Connection::server returned improper connection header line',
);
}
if (!headers.containsKey('upgrade') ||
headers['upgrade']!.toLowerCase() != 'websocket') {
throw MqttNoConnectionException(
'MqttServerWs2Connection::server returned improper upgrade header line',
);
}
if (!headers.containsKey('sec-websocket-protocol')) {
throw MqttNoConnectionException(
'MqttServerWs2Connection::server failed to return protocol header',
);
}
if (!headers.containsKey('sec-websocket-accept')) {
throw MqttNoConnectionException(
'MqttServerWs2Connection::server failed to return accept header',
);
}
// We build up the accept in the same way the server should
// then we check that the response is the same.
// Do not change: https://tools.ietf.org/html/rfc6455#section-1.3
const acceptSalt = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
final sha1Bytes = sha1.convert(utf8.encode(key + acceptSalt));
final encodedSha1Bytes = base64.encode(sha1Bytes.bytes);
if (encodedSha1Bytes != headers['sec-websocket-accept']) {
throw MqttNoConnectionException(
'MqttServerWs2Connection::handshake mismatch',
);
}
return false;
}