Skip to content

Commit e0b4e93

Browse files
committed
fix: replace BufferedReader with BufferedInputStream for accurate byte reading in JSON-RPC client
1 parent ea81206 commit e0b4e93

1 file changed

Lines changed: 37 additions & 19 deletions

File tree

src/main/java/com/github/copilot/sdk/JsonRpcClient.java

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44

55
package com.github.copilot.sdk;
66

7-
import java.io.BufferedReader;
7+
import java.io.BufferedInputStream;
88
import java.io.IOException;
99
import java.io.InputStream;
10-
import java.io.InputStreamReader;
1110
import java.io.OutputStream;
1211
import java.net.Socket;
1312
import java.nio.charset.StandardCharsets;
@@ -185,42 +184,61 @@ private synchronized void sendMessage(Object message) throws IOException {
185184
private void startReader() {
186185
readerExecutor.submit(() -> {
187186
try {
188-
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
187+
// We need to read bytes because Content-Length specifies bytes, not characters.
188+
// Using BufferedReader would cause issues with multi-byte UTF-8 characters.
189+
BufferedInputStream bis = new BufferedInputStream(inputStream);
189190

190191
while (running) {
191-
String line = reader.readLine();
192-
if (line == null) {
193-
break;
194-
}
195-
196-
// Parse headers
192+
// Read headers line by line
197193
int contentLength = -1;
198-
while (!line.isEmpty()) {
199-
if (line.toLowerCase().startsWith("content-length:")) {
200-
contentLength = Integer.parseInt(line.substring(15).trim());
201-
}
202-
line = reader.readLine();
203-
if (line == null) {
194+
StringBuilder headerLine = new StringBuilder();
195+
boolean lastWasCR = false;
196+
boolean inHeaders = true;
197+
198+
while (inHeaders) {
199+
int b = bis.read();
200+
if (b == -1) {
204201
return;
205202
}
203+
204+
if (b == '\r') {
205+
lastWasCR = true;
206+
} else if (b == '\n') {
207+
String line = headerLine.toString();
208+
headerLine.setLength(0);
209+
lastWasCR = false;
210+
211+
if (line.isEmpty()) {
212+
// End of headers (blank line)
213+
inHeaders = false;
214+
} else if (line.toLowerCase().startsWith("content-length:")) {
215+
contentLength = Integer.parseInt(line.substring(15).trim());
216+
}
217+
} else {
218+
if (lastWasCR) {
219+
headerLine.append('\r');
220+
lastWasCR = false;
221+
}
222+
headerLine.append((char) b);
223+
}
206224
}
207225

208226
if (contentLength <= 0) {
209227
continue;
210228
}
211229

212-
// Read content
213-
char[] buffer = new char[contentLength];
230+
// Read content as bytes (Content-Length specifies bytes, not characters)
231+
byte[] buffer = new byte[contentLength];
214232
int read = 0;
215233
while (read < contentLength) {
216-
int result = reader.read(buffer, read, contentLength - read);
234+
int result = bis.read(buffer, read, contentLength - read);
217235
if (result == -1) {
218236
return;
219237
}
220238
read += result;
221239
}
222240

223-
String content = new String(buffer);
241+
String content = new String(buffer, StandardCharsets.UTF_8);
224242
LOG.fine("Received: " + content);
225243

226244
handleMessage(content);

0 commit comments

Comments
 (0)