Skip to content

Commit 1123046

Browse files
bwilkersonCommit Queue
authored andcommitted
Fix the handling of LSP headers
The invalid handling of LSP headers caused the analysis server, in LSP mode, to not recognize any of the messages being sent to it. Change-Id: I03b3c8e22216f3451401823dd62a49a984edc550 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/464626 Commit-Queue: Brian Wilkerson <[email protected]> Reviewed-by: Keerti Parthasarathy <[email protected]>
1 parent 2a44627 commit 1123046

File tree

2 files changed

+45
-7
lines changed

2 files changed

+45
-7
lines changed

pkg/analysis_server/tool/log_player/log_player.dart

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'package:analysis_server/src/server/driver.dart';
66
import 'package:analysis_server/src/session_logger/entry_kind.dart';
77
import 'package:analysis_server/src/session_logger/log_entry.dart';
88
import 'package:analysis_server/src/session_logger/process_id.dart';
9+
import 'package:collection/collection.dart';
910

1011
import 'log.dart';
1112
import 'server_driver.dart';
@@ -48,6 +49,10 @@ class LogPlayer {
4849
'Analysis server already started, only one instance is allowed.',
4950
);
5051
}
52+
// TODO(brianwilkerson): Stop parsing out the protocol. Instead,
53+
// consider verifying that a protocol was specified, throwing if not,
54+
// and then just pass all of the arguments to the constructor. This
55+
// would require allow-listing the protocol option.
5156
var parsedArgs = driverArgParser.parse(entry.argList);
5257
var protocolOption = parsedArgs.option(Driver.serverProtocolOption);
5358
var protocol = switch (protocolOption) {
@@ -56,7 +61,12 @@ class LogPlayer {
5661
_ => throw StateError('Unrecognized protocol $protocolOption'),
5762
};
5863
var server = this.server = ServerDriver(protocol: protocol);
59-
server.additionalArguments.addAll(entry.argList);
64+
server.additionalArguments.addAll(
65+
entry.argList.whereNot(
66+
(element) =>
67+
element.startsWith('--${Driver.serverProtocolOption}'),
68+
),
69+
);
6070
await server.start();
6171
case EntryKind.message:
6272
if (entry.receiver == ProcessId.server) {
@@ -65,7 +75,7 @@ class LogPlayer {
6575
_handleMessageFromServer(entry);
6676
} else {
6777
throw StateError('''
68-
Unexpected sender/reciever for message:
78+
Unexpected sender/receiver for message:
6979
7080
sender: ${entry.sender}
7181
receiver: ${entry.receiver}
@@ -74,12 +84,14 @@ receiver: ${entry.receiver}
7484
}
7585
nextIndex++;
7686
}
87+
await _readMessagesFromServer();
7788
if (!_hasSeenShutdown) {
7889
server?.shutdown();
7990
}
8091
if (!_hasSeenExit) {
8192
server?.exit();
8293
}
94+
await _readMessagesFromServer();
8395
server = null;
8496
}
8597

@@ -112,6 +124,12 @@ receiver: ${entry.receiver}
112124
}
113125
}
114126

127+
/// Wait for the server to process any messages that it may have received and
128+
/// for any responses to be sent back.
129+
Future<void> _readMessagesFromServer() async {
130+
await Future.delayed(const Duration(seconds: 1));
131+
}
132+
115133
/// Sends the message in the [entry] to the server.
116134
Future<void> _sendMessageToServer(LogEntry entry) async {
117135
var server = this.server;

pkg/analysis_server/tool/log_player/server_driver.dart

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'dart:convert';
66
import 'dart:io';
77

88
import 'package:analysis_server/lsp_protocol/protocol.dart' show jsonRpcVersion;
9+
import 'package:analysis_server/src/lsp/lsp_packet_transformer.dart';
910
import 'package:analysis_server/src/server/driver.dart';
1011
import 'package:analysis_server/src/session_logger/log_entry.dart';
1112

@@ -109,7 +110,20 @@ class ServerDriver {
109110
/// used by the IDE.
110111
void sendMessageFromIde(Message message) {
111112
if (_stdinSink case IOSink writeSink) {
112-
writeSink.writeln(json.encode(message));
113+
var jsonEncodedBody = jsonEncode(message);
114+
if (_protocol == ServerProtocol.lsp) {
115+
var utf8EncodedBody = utf8.encode(jsonEncodedBody);
116+
var header =
117+
'Content-Length: ${utf8EncodedBody.length}\r\n'
118+
'Content-Type: application/vscode-jsonrpc; charset=utf-8\r\n\r\n';
119+
var asciiEncodedHeader = ascii.encode(header);
120+
121+
// Header is always ascii, body is always utf8!
122+
writeSink.add(asciiEncodedHeader);
123+
writeSink.add(utf8EncodedBody);
124+
} else {
125+
writeSink.write(jsonEncodedBody);
126+
}
113127
} else {
114128
throw StateError(
115129
"The method 'start' must be invoked before "
@@ -164,10 +178,16 @@ class ServerDriver {
164178
...filteredAdditionalArguments,
165179
]);
166180
_stdinSink = process.stdin;
167-
process.stdout
168-
.transform(const Utf8Decoder())
169-
.transform(const LineSplitter())
170-
.listen(_receiveMessageFromServer);
181+
if (_protocol == ServerProtocol.lsp) {
182+
process.stdout
183+
.transform(LspPacketTransformer())
184+
.listen(_receiveMessageFromServer);
185+
} else {
186+
process.stdout
187+
.transform(const Utf8Decoder())
188+
.transform(const LineSplitter())
189+
.listen(_receiveMessageFromServer);
190+
}
171191
}
172192

173193
void _receiveMessageFromServer(String message) {

0 commit comments

Comments
 (0)