diff --git a/samples/AzCopyCore/AzCopyCore/AzCopyCore.csproj b/samples/AzCopyCore/AzCopyCore/AzCopyCore.csproj
index 141dd99c4c2..6567f2197ab 100644
--- a/samples/AzCopyCore/AzCopyCore/AzCopyCore.csproj
+++ b/samples/AzCopyCore/AzCopyCore/AzCopyCore.csproj
@@ -17,13 +17,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/samples/AzCopyCore/AzCopyCore/SocketClient.cs b/samples/AzCopyCore/AzCopyCore/SocketClient.cs
index 0883035a290..6b6e3de803f 100644
--- a/samples/AzCopyCore/AzCopyCore/SocketClient.cs
+++ b/samples/AzCopyCore/AzCopyCore/SocketClient.cs
@@ -86,11 +86,40 @@ public async ValueTask SendRequest(TRequest requ
await request.WriteAsync(_requestPipe.Writer).ConfigureAwait(false);
var reader = _responsePipe.Reader;
- var response = await HttpExtensions.ParseAsync(reader, Log).ConfigureAwait(false);
+ var response = await ParseAsync(reader, Log).ConfigureAwait(false);
response.OnBody(reader);
return response;
}
+ static HttpParser s_headersParser = new HttpParser();
+
+ // TODO (pri 3): Add to the platform, but this would require common logging API
+ public static async ValueTask ParseAsync(PipeReader reader, TraceSource log = null)
+ where T : IHttpResponseLineHandler, IHttpHeadersHandler, new()
+ {
+ var result = await reader.ReadAsync();
+ ReadOnlySequence buffer = result.Buffer;
+
+ if (log != null) log.WriteInformation("RESPONSE: ", buffer.First);
+
+ var handler = new T();
+ // TODO (pri 2): this should not be static, or all should be static
+ if (!HttpParser.ParseResponseLine(ref handler, ref buffer, out int rlConsumed))
+ {
+ throw new NotImplementedException("could not parse the response");
+ }
+
+ buffer = buffer.Slice(rlConsumed);
+ if (!s_headersParser.ParseHeaders(ref handler, buffer, out int hdConsumed))
+ {
+ throw new NotImplementedException("could not parse the response");
+ }
+
+ reader.AdvanceTo(buffer.GetPosition(buffer.Start, hdConsumed));
+
+ return handler;
+ }
+
async Task SendAsync()
{
var reader = _requestPipe.Reader;
diff --git a/samples/AzCopyCore/AzCopyCore/StorageRequests.cs b/samples/AzCopyCore/AzCopyCore/StorageRequests.cs
index eb7ca47bfc4..c0b9ec651ec 100644
--- a/samples/AzCopyCore/AzCopyCore/StorageRequests.cs
+++ b/samples/AzCopyCore/AzCopyCore/StorageRequests.cs
@@ -5,6 +5,7 @@
using System.IO;
using System.IO.Pipelines;
using System.Net.Experimental;
+using System.Text;
using System.Text.Http.Formatter;
using System.Text.Http.Parser;
using System.Threading.Tasks;
@@ -71,11 +72,12 @@ protected virtual void WriteOtherHeaders(ref BufferWriter writer, ref T argument
writer.WriteHeader("Host", arguments.Client.Host);
}
- // TODO (pri 2): this should be UTF8
- public static string AsString(Http.Method verb)
+ static readonly byte[] s_GETu8 = Encoding.ASCII.GetBytes("GET");
+ static readonly byte[] s_PUTu8 = Encoding.ASCII.GetBytes("PUT");
+ public static ReadOnlyMemory AsString(Http.Method verb)
{
- if (verb == Http.Method.Get) return "GET";
- if (verb == Http.Method.Put) return "PUT";
+ if (verb == Http.Method.Get) return s_GETu8;
+ if (verb == Http.Method.Put) return s_PUTu8;
throw new NotImplementedException();
}
}
diff --git a/samples/AzCopyCore/AzCopyCore/temp/Extensions.cs b/samples/AzCopyCore/AzCopyCore/temp/Extensions.cs
index 3965d3f6200..f3f6042b29e 100644
--- a/samples/AzCopyCore/AzCopyCore/temp/Extensions.cs
+++ b/samples/AzCopyCore/AzCopyCore/temp/Extensions.cs
@@ -2,7 +2,6 @@
using System.Diagnostics;
using System.IO;
using System.IO.Pipelines;
-using System.Text;
using System.Text.Http.Parser;
using System.Threading.Tasks;
@@ -12,9 +11,9 @@ namespace System.Buffers
static class GeneralExtensions
{
///
- /// Copies bytes from ReadOnlyBuffer to a Stream
+ /// Copies bytes from ReadOnlySequence to a Stream
///
- public static async Task WriteAsync(this Stream stream, ReadOnlyBuffer buffer)
+ public static async Task WriteAsync(this Stream stream, ReadOnlySequence buffer)
{
for (var position = buffer.Start; buffer.TryGet(ref position, out var memory);)
{
@@ -30,7 +29,7 @@ public static async Task WriteAsync(this Stream stream, PipeReader reader, ulong
while (bytes > 0)
{
var result = await reader.ReadAsync();
- ReadOnlyBuffer bodyBuffer = result.Buffer;
+ ReadOnlySequence bodyBuffer = result.Buffer;
if (bytes < (ulong)bodyBuffer.Length)
{
throw new NotImplementedException();
@@ -84,104 +83,6 @@ public static void WriteError(this TraceSource source, string message)
}
}
- public static class HttpExtensions
- {
- static HttpParser s_headersParser = new HttpParser();
- private const byte ByteLF = (byte)'\n';
- private const byte ByteCR = (byte)'\r';
- private const long maxRequestLineLength = 1024;
- static readonly byte[] s_Eol = Encoding.ASCII.GetBytes("\r\n");
- static readonly byte[] s_http11 = Encoding.ASCII.GetBytes("HTTP/1.1");
- static readonly byte[] s_http10 = Encoding.ASCII.GetBytes("HTTP/1.0");
- static readonly byte[] s_http20 = Encoding.ASCII.GetBytes("HTTP/2.0");
-
- // TODO (pri 2): move to corfxlab
- public static bool ParseResponseLine(ref T handler, ref ReadOnlyBuffer buffer, out int consumedBytes) where T : IHttpResponseLineHandler
- {
- var line = buffer.First.Span;
- var lf = line.IndexOf(ByteLF);
- if (lf >= 0)
- {
- line = line.Slice(0, lf + 1);
- }
- else if (buffer.IsSingleSegment)
- {
- consumedBytes = 0;
- return false;
- }
- else
- {
- long index = Sequence.IndexOf(buffer, ByteLF);
- if(index < 0)
- {
- consumedBytes = 0;
- return false;
- }
- if(index > maxRequestLineLength)
- {
- throw new Exception("invalid response (LF too far)");
- }
- line = line.Slice(0, lf + 1);
- }
-
- if(line[lf - 1] != ByteCR)
- {
- throw new Exception("invalid response (no CR)");
- }
-
- Http.Version version;
- if (line.StartsWith(s_http11)) { version = Http.Version.Http11; }
- // TODO (pri 2): add HTTP2 to HTTP.Version
- else if (line.StartsWith(s_http20)) { version = Http.Version.Unknown; }
- else if (line.StartsWith(s_http10)) { version = Http.Version.Http10; }
- else
- {
- throw new Exception("invalid response (version)");
- }
-
- int codeStart = line.IndexOf((byte)' ') + 1;
- var codeSlice = line.Slice(codeStart);
- if (!Utf8Parser.TryParse(codeSlice, out ushort code, out consumedBytes))
- {
- throw new Exception("invalid response (status code)");
- }
-
- var reasonStart = consumedBytes + 1;
- var reason = codeSlice.Slice(reasonStart, codeSlice.Length - reasonStart - 2);
- consumedBytes = lf + s_Eol.Length;
-
- handler.OnStatusLine(version, code, reason);
-
- return true;
- }
-
- // TODO (pri 3): Add to the platform, but this would require common logging API
- public static async ValueTask ParseAsync(PipeReader reader, TraceSource log = null)
- where T : IHttpResponseLineHandler, IHttpHeadersHandler, new()
- {
- var result = await reader.ReadAsync();
- ReadOnlyBuffer buffer = result.Buffer;
-
- if (log != null) log.WriteInformation("RESPONSE: ", buffer.First);
-
- var handler = new T();
- if (!ParseResponseLine(ref handler, ref buffer, out int rlConsumed))
- {
- throw new NotImplementedException("could not parse the response");
- }
-
- buffer = buffer.Slice(rlConsumed);
- if (!s_headersParser.ParseHeaders(ref handler, buffer, out int hdConsumed))
- {
- throw new NotImplementedException("could not parse the response");
- }
-
- reader.AdvanceTo(buffer.GetPosition(buffer.Start, hdConsumed));
-
- return handler;
- }
- }
-
// TODO (pri 3): Should I use the command line library?
class CommandOptions
{