static async Task <PhpValue> ProcessResponse(Context ctx, CURLResource ch, HttpWebResponse response) { // in case we are returning the response value var returnstream = ch.ProcessingResponse.Method == ProcessMethodEnum.RETURN ? new MemoryStream() : null; // handle headers if (!ch.ProcessingHeaders.IsEmpty) { var statusHeaders = HttpHeaders.StatusHeader(response) + HttpHeaders.HeaderSeparator; // HTTP/1.1 xxx xxx\r\n Stream outputHeadersStream = null; switch (ch.ProcessingHeaders.Method) { case ProcessMethodEnum.RETURN: case ProcessMethodEnum.STDOUT: outputHeadersStream = (returnstream ?? ctx.OutputStream); goto default; case ProcessMethodEnum.FILE: outputHeadersStream = ch.ProcessingHeaders.Stream.RawStream; goto default; case ProcessMethodEnum.USER: // pass headers one by one, // in original implementation we should pass them as they are read from socket: ch.ProcessingHeaders.User.Invoke(ctx, new[] { PhpValue.FromClass(ch), PhpValue.Create(statusHeaders) }); for (int i = 0; i < response.Headers.Count; i++) { var key = response.Headers.GetKey(i); var value = response.Headers.Get(i); if (key == null || key.Length != 0) { // header ch.ProcessingHeaders.User.Invoke(ctx, new[] { PhpValue.FromClr(ch), PhpValue.Create(key + ": " + value + HttpHeaders.HeaderSeparator), }); } } // \r\n ch.ProcessingHeaders.User.Invoke(ctx, new[] { PhpValue.FromClr(ch), PhpValue.Create(HttpHeaders.HeaderSeparator) }); break; default: if (outputHeadersStream != null) { await outputHeadersStream.WriteAsync(Encoding.ASCII.GetBytes(statusHeaders)); await outputHeadersStream.WriteAsync(response.Headers.ToByteArray()); } else { Debug.Fail("Unexpected ProcessingHeaders " + ch.ProcessingHeaders.Method); } break; } } var stream = response.GetResponseStream(); // gzip decode if necessary if (response.ContentEncoding == "gzip") // TODO: // && ch.AcceptEncoding.Contains("gzip") ?? { ch.VerboseOutput("Decompressing the output stream using GZipStream."); stream = new GZipStream(stream, CompressionMode.Decompress, leaveOpen: false); } // read into output stream: switch (ch.ProcessingResponse.Method) { case ProcessMethodEnum.STDOUT: await stream.CopyToAsync(ctx.OutputStream); break; case ProcessMethodEnum.RETURN: stream.CopyTo(returnstream); break; case ProcessMethodEnum.FILE: await stream.CopyToAsync(ch.ProcessingResponse.Stream.RawStream); break; case ProcessMethodEnum.USER: if (response.ContentLength != 0) { // preallocate a buffer to read to, // this should be according to PHP's behavior and slightly more effective than memory stream byte[] buffer = new byte[ch.BufferSize > 0 ? ch.BufferSize : 2048]; int bufferread; while ((bufferread = stream.Read(buffer, 0, buffer.Length)) > 0) { ch.ProcessingResponse.User.Invoke(ctx, new[] { PhpValue.FromClr(ch), PhpValue.Create(new PhpString(buffer.AsSpan(0, bufferread).ToArray())), // clone the array and pass to function }); } } break; case ProcessMethodEnum.IGNORE: break; } // stream.Dispose(); stream = null; // return((returnstream != null) ? PhpValue.Create(new PhpString(returnstream.ToArray())) : PhpValue.True); }
static PhpValue ProcessResponse(Context ctx, CURLResource ch, HttpWebResponse response) { // in case we are returning the response value var returnstream = ch.ProcessingResponse.Method == ProcessMethodEnum.RETURN ? new MemoryStream() : null; // handle headers if (!ch.ProcessingHeaders.IsEmpty) { switch (ch.ProcessingHeaders.Method) { case ProcessMethodEnum.RETURN: case ProcessMethodEnum.STDOUT: (returnstream ?? ctx.OutputStream).Write(response.Headers.ToByteArray()); break; case ProcessMethodEnum.FILE: ch.ProcessingHeaders.Stream.RawStream.Write(response.Headers.ToByteArray()); break; case ProcessMethodEnum.USER: // pass headers one by one, // in original implementation we should pass them as they are read from socket: ch.ProcessingHeaders.User.Invoke(ctx, new[] { PhpValue.FromClr(ch), PhpValue.Create(HttpHeaders.StatusHeader(response) + HttpHeaders.HeaderSeparator) }); for (int i = 0; i < response.Headers.Count; i++) { // header ch.ProcessingHeaders.User.Invoke(ctx, new[] { PhpValue.FromClr(ch), PhpValue.Create(response.Headers[i] + HttpHeaders.HeaderSeparator), }); } // \r\n ch.ProcessingHeaders.User.Invoke(ctx, new[] { PhpValue.FromClr(ch), PhpValue.Create(HttpHeaders.HeaderSeparator) }); break; default: Debug.Fail("Unexpected ProcessingHeaders " + ch.ProcessingHeaders.Method); break; } } var stream = response.GetResponseStream(); // read into output stream: switch (ch.ProcessingResponse.Method) { case ProcessMethodEnum.STDOUT: stream.CopyTo(ctx.OutputStream); break; case ProcessMethodEnum.RETURN: stream.CopyTo(returnstream); break; case ProcessMethodEnum.FILE: stream.CopyTo(ch.ProcessingResponse.Stream.RawStream); break; case ProcessMethodEnum.USER: if (response.ContentLength != 0) { // preallocate a buffer to read to, // this should be according to PHP's behavior and slightly more effective than memory stream byte[] buffer = new byte[ch.BufferSize > 0 ? ch.BufferSize : 2048]; int bufferread; while ((bufferread = stream.Read(buffer, 0, buffer.Length)) > 0) { ch.ProcessingResponse.User.Invoke(ctx, new[] { PhpValue.FromClr(ch), PhpValue.Create(new PhpString(buffer.AsSpan(0, bufferread).ToArray())), // clone the array and pass to function }); } } break; case ProcessMethodEnum.IGNORE: break; } // return((returnstream != null) ? PhpValue.Create(new PhpString(returnstream.ToArray())) : PhpValue.True); }