<commit_before>﻿using System;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Proxy.Headers;
using Proxy.Tunnels;

namespace Proxy.ProxyHandlerNext
{
    public class HttpHandler : IHandler
    {
        private const int BufferSize = 8192;

        public async Task<HandlerResult> Run(Context context)
        {
            if (context.CurrentHostAddress == null || !Equals(context.Header.Host, context.CurrentHostAddress))
            {
                return HandlerResult.NewHostRequired;
            }

            var buffer = new byte[BufferSize];

            var oneWayTunnel = Tunnel(context.HostStream, context.ClientStream);

            try
            {
                int bytesRead;

                do
                {
                    context.Header = await GetHeader(context.Header, context.ClientStream);

                    if (context.Header == null)
                    {
                        return HandlerResult.Terminated;
                    }

                    if (context.CurrentHostAddress == null || !Equals(context.Header.Host, context.CurrentHostAddress))
                    {
                        TerminateHost(oneWayTunnel);

                        return HandlerResult.NewHostRequired;
                    }

                    bytesRead = await ForwardHeader(context.Header, context.HostStream);

                    if (HasBody(context.Header))
                    {
                        bytesRead = await ForwardBody(context.ClientStream, context.HostStream, context.Header.ContentLength, buffer);
                    }

                    context.Header = null;
                } while (bytesRead > 0);
            }
            finally
            {
                TerminateHost(oneWayTunnel);
            }

            return HandlerResult.Terminated;
        }

        private static async Task<HttpHeader> GetHeader(HttpHeader header, NetworkStream stream)
        {
            return header ?? await new HttpHeaderStream().GetHeader(stream, CancellationToken.None);
        }

        private static void TerminateHost(params IDisposable[] objects)
        {
            foreach (var disposable in objects)
            {
                using (disposable)
                {
                }
            }
        }

        private static TcpOneWayTunnel Tunnel(NetworkStream source, NetworkStream destination)
        {
            var tunnel = new TcpOneWayTunnel();
            tunnel.Run(destination, source).GetAwaiter();
            return tunnel;
        }

        private static async Task<int> ForwardHeader(HttpHeader httpHeader, NetworkStream host)
        {
            await host.WriteAsync(httpHeader.Array, 0, httpHeader.Array.Length);
            return httpHeader.Array.Length;
        }

        private static bool HasBody(HttpHeader header)
        {
            return header.ContentLength > 0;
        }

        private static async Task<int> ForwardBody(Stream client, Stream host, long contentLength, byte[] buffer)<commit_msg>Http handler refactor<commit_after>﻿using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Proxy.Headers;
using Proxy.Tunnels;

namespace Proxy.ProxyHandlerNext
{
    public class HttpHandler : IHandler
    {
        private const int BufferSize = 8192;

        public async Task<HandlerResult> Run(Context context)
        {
            if (IsNewHostRequired(context))
            {
                return HandlerResult.NewHostRequired;
            }

            using (OneWayTunnel(context.HostStream, context.ClientStream))
            {
                var buffer = new byte[BufferSize];
                int bytesRead;

                do
                {
                    context.Header = await GetHeader(context.Header, context.ClientStream);

                    if (context.Header == null)
                    {
                        return HandlerResult.Terminated;
                    }

                    if (IsNewHostRequired(context))
                    {
                        return HandlerResult.NewHostRequired;
                    }

                    bytesRead = await ForwardHeader(context.Header, context.HostStream);

                    if (HasBody(context.Header))
                    {
                        bytesRead = await ForwardBody(context.ClientStream, context.HostStream, context.Header.ContentLength, buffer);
                    }

                    context.Header = null;
                } while (bytesRead > 0);
            }

            return HandlerResult.Terminated;
        }

        private static bool IsNewHostRequired(Context context)
        {
            return context.CurrentHostAddress == null || !Equals(context.Header.Host, context.CurrentHostAddress);
        }

        private static TcpOneWayTunnel OneWayTunnel(NetworkStream source, NetworkStream destination)
        {
            var tunnel = new TcpOneWayTunnel();
            tunnel.Run(destination, source).GetAwaiter();
            return tunnel;
        }

        private static async Task<HttpHeader> GetHeader(HttpHeader header, Stream stream)
        {
            return header ?? await new HttpHeaderStream().GetHeader(stream, CancellationToken.None);
        }

        private static async Task<int> ForwardHeader(HttpHeader httpHeader, Stream host)
        {
            await host.WriteAsync(httpHeader.Array, 0, httpHeader.Array.Length);
            return httpHeader.Array.Length;
        }

        private static bool HasBody(HttpHeader header)
        {
            return header.ContentLength > 0;
        }

        private static async Task<int> ForwardBody(Stream client, Stream host, long contentLength, byte[] buffer)
{'fraction_non_alphanumeric': 0.0734229576008273, 'fraction_numerical': 0.002412961047914512, 'mean_word_length': 1.648562300319489, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6422364', 'n_tokens_mistral': 1418, 'n_tokens_neox': 1310, 'n_words': 311}