Skip to content

Commit cea6c78

Browse files
committed
improve handling of newline characters of the command line
1 parent 11341a1 commit cea6c78

File tree

2 files changed

+32
-9
lines changed

2 files changed

+32
-9
lines changed

src/Smdn.Net.MuninNode/Smdn.Net.MuninNode/NodeBase.cs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -538,16 +538,27 @@ await RespondToCommandAsync(
538538
static bool TryReadLine(ref ReadOnlySequence<byte> buffer, out ReadOnlySequence<byte> line)
539539
{
540540
var reader = new SequenceReader<byte>(buffer);
541+
const byte CR = (byte)'\r';
541542
const byte LF = (byte)'\n';
542543

543-
if (
544-
!reader.TryReadTo(out line, delimiter: "\r\n"u8, advancePastDelimiter: true) &&
545-
!reader.TryReadTo(out line, delimiter: LF, advancePastDelimiter: true)
546-
) {
544+
// read sequence until LF
545+
if (!reader.TryReadTo(out line, delimiter: LF, advancePastDelimiter: true)) {
547546
line = default;
548547
return false;
549548
}
550549

550+
// trim the CR just before the LF, in case the line ends with CRLF
551+
var lineLength = line.Length;
552+
553+
if (0 < lineLength) {
554+
var lineReader = new SequenceReader<byte>(line);
555+
556+
lineReader.Advance(lineLength - 1);
557+
558+
if (lineReader.UnreadSpan[0] == CR)
559+
line = line.Slice(0, lineLength - 1);
560+
}
561+
551562
#if SYSTEM_BUFFERS_SEQUENCEREADER_UNREADSEQUENCE
552563
buffer = reader.UnreadSequence;
553564
#else

tests/Smdn.Net.MuninNode/Smdn.Net.MuninNode/NodeBase.Commands.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,14 @@ private static async Task RunSessionAsync(
118118
}
119119
}
120120

121-
[TestCase("\r\n")]
122-
[TestCase("\n")]
121+
[TestCase("\r\n", "# Unknown command.")]
122+
[TestCase("\n", "# Unknown command.")]
123+
[TestCase("foo\r\n", "# Unknown command.")]
124+
[TestCase("foo\n", "# Unknown command.")]
125+
[TestCase(".\r\n", null)]
126+
[TestCase(".\n", null)]
123127
[CancelAfter(3000)]
124-
public async Task ProcessCommandAsync_EndOfLine(string eol, CancellationToken cancellationToken)
128+
public async Task ProcessCommandAsync_EndOfLine(string commandLine, string? expectedResponseLinePrefix, CancellationToken cancellationToken)
125129
{
126130
PseudoMuninNodeClient? acceptedClient = null;
127131

@@ -131,9 +135,17 @@ await RunSessionAsync(
131135
async (node, client, writer, reader, ct) => {
132136
Assert.That(client.IsConnected, Is.True);
133137

134-
await writer.WriteAsync(("." + eol).AsMemory(), ct);
135-
136138
acceptedClient = client;
139+
140+
await writer.WriteAsync(commandLine.AsMemory(), ct);
141+
await writer.FlushAsync(ct);
142+
143+
Assert.That(
144+
await reader.ReadLineAsync(ct),
145+
expectedResponseLinePrefix is null
146+
? Is.Null
147+
: Does.StartWith(expectedResponseLinePrefix)
148+
);
137149
},
138150
cancellationToken: cancellationToken
139151
);

0 commit comments

Comments
 (0)