|
5 | 5 | #if FEATURE_FULL_NET |
6 | 6 |
|
7 | 7 | using System; |
| 8 | +using System.Buffers; |
8 | 9 | using System.Collections.Generic; |
9 | 10 | using System.Diagnostics; |
10 | 11 | using System.Globalization; |
@@ -593,30 +594,61 @@ public string issuer() { |
593 | 594 |
|
594 | 595 | [Documentation(@"read(size, [buffer]) |
595 | 596 | Read up to size bytes from the SSL socket.")] |
596 | | - public object read(CodeContext/*!*/ context, int size, ByteArray buffer = null) { |
| 597 | + public Bytes read(CodeContext/*!*/ context, int size) { |
597 | 598 | EnsureSslStream(true); |
598 | 599 |
|
| 600 | + if (size < 0) throw PythonOps.ValueError("size should not be negative"); |
| 601 | + |
| 602 | + var buf = ArrayPool.Rent(size); |
599 | 603 | try { |
600 | | - byte[] buf = new byte[2048]; |
601 | | - MemoryStream result = new MemoryStream(size); |
602 | | - while (true) { |
603 | | - int readLength = (size < buf.Length) ? size : buf.Length; |
604 | | - int bytes = _sslStream.Read(buf, 0, readLength); |
605 | | - if (bytes > 0) { |
606 | | - result.Write(buf, 0, bytes); |
607 | | - size -= bytes; |
608 | | - } |
| 604 | + int numRead; |
| 605 | + try { |
| 606 | + numRead = _sslStream.Read(buf, 0, size); |
| 607 | + } catch (Exception e) { |
| 608 | + throw PythonSocket.MakeException(context, e); |
| 609 | + } |
| 610 | + |
| 611 | + var bytes = new byte[numRead]; |
| 612 | + Array.Copy(buf, bytes, bytes.Length); |
| 613 | + return Bytes.Make(bytes); |
| 614 | + } finally { |
| 615 | + ArrayPool.Return(buf); |
| 616 | + } |
| 617 | + } |
| 618 | + |
| 619 | + private static ArrayPool<byte> ArrayPool => ArrayPool<byte>.Shared; |
| 620 | + |
| 621 | + [Documentation(@"read(size, [buffer]) |
| 622 | +Read up to size bytes from the SSL socket.")] |
| 623 | + public int read(CodeContext/*!*/ context, int size, [NotNone] IBufferProtocol buffer) { |
| 624 | + EnsureSslStream(true); |
| 625 | + |
| 626 | + using var pythonBuffer = buffer.GetBufferNoThrow(BufferFlags.Writable) |
| 627 | + ?? throw PythonOps.TypeError("read() argument 2 must be read-write bytes-like object, not {0}", PythonOps.GetPythonTypeName(buffer)); |
609 | 628 |
|
610 | | - if (bytes == 0 || size == 0 || bytes < readLength) { |
611 | | - var res = result.ToArray(); |
612 | | - if (buffer == null) |
613 | | - return Bytes.Make(res); |
| 629 | + var bufferLen = pythonBuffer.ItemCount; |
| 630 | + if (size <= 0 || bufferLen < size) size = bufferLen; |
614 | 631 |
|
615 | | - // TODO: get rid of the MemoryStream and write directly to the buffer |
616 | | - buffer[new Slice(0, res.Length)] = res; |
617 | | - return res.Length; |
| 632 | + try { |
| 633 | +#if NETCOREAPP |
| 634 | + return _sslStream.Read(pythonBuffer.AsSpan().Slice(0, size)); |
| 635 | +#else |
| 636 | + var buf = pythonBuffer.AsUnsafeWritableArray(); |
| 637 | + if (buf is null) { |
| 638 | + buf = ArrayPool.Rent(size); |
| 639 | + try { |
| 640 | + var numRead = _sslStream.Read(buf, 0, size); |
| 641 | + buf.AsSpan(0, numRead).CopyTo(pythonBuffer.AsSpan()); |
| 642 | + return numRead; |
| 643 | + } |
| 644 | + finally { |
| 645 | + ArrayPool.Return(buf); |
618 | 646 | } |
619 | 647 | } |
| 648 | + else { |
| 649 | + return _sslStream.Read(buf, 0, size); |
| 650 | + } |
| 651 | +#endif |
620 | 652 | } catch (Exception e) { |
621 | 653 | throw PythonSocket.MakeException(context, e); |
622 | 654 | } |
|
0 commit comments