<commit_before>package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"net"
	"os"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"time"
)

// Lots of the code here are learnt from the http package

type Proxy struct {
	addr string // listen address
}

type connType byte

const (
	nilConn connType = iota
	directConn
	socksConn
)

type handlerState byte

const (
	hsConnected handlerState = iota
	hsResponsReceived
	hsStopped
)

type conn struct {
	net.Conn
	connType
}

type Handler struct {
	conn
	buf     *bufio.ReadWriter
	host    string
	state   handlerState
	lastUse time.Time
}

var one = make([]byte, 1)

func newHandler(c conn, host string) *Handler {
	return &Handler{
		conn: c,
		host: host,
		buf: bufio.NewReadWriter(bufio.NewReaderSize(c, bufSize),
			bufio.NewWriter(c)),
	}
}

type clientConn struct {
	buf      *bufio.ReadWriter
	net.Conn                     // connection to the proxy client
	handler  map[string]*Handler // request handler, host:port as key
}

var (
	errRetry    = errors.New("Retry")
	errPageSent = errors.New("Error page has sent")
)

func NewProxy(addr string) *Proxy {
	return &Proxy{addr: addr}
}

func (py *Proxy) Serve() {
	ln, err := net.Listen("tcp", py.addr)
	if err != nil {
		fmt.Println("Server creation failed:", err)
		os.Exit(1)
	}
	info.Println("COW proxy listening", py.addr)

	for {
		conn, err := ln.Accept()
		if err != nil {
			debug.Println("Client connection:", err)
			continue
		}
		if debug {
			debug.Println("New Client:", conn.RemoteAddr())
		}
		c := newClientConn(conn)
		go c.serve()
	}
}

// Explicitly specify buffer size to avoid unnecessary copy using
// bufio.Reader's Read
const bufSize = 4096

func newClientConn(rwc net.Conn) *clientConn {
	c := &clientConn{
		Conn:    rwc,
		handler: map[string]*Handler{},
		buf: bufio.NewReadWriter(bufio.NewReaderSize(rwc, bufSize),
			bufio.NewWriter(rwc)),
	}
	return c
}

func (c *clientConn) close() {
	c.buf = nil
	c.Close()
	if debug {
		debug.Printf("Client %v connection closed\n", c.RemoteAddr())
	}
	runtime.GC()
}

func isSelfURL(h string) bool {
	return h == "" || h == selfURL127 || h == selfURLLH
}

func (c *clientConn) getRequest() (r *Request) {
	var err error
	if r, err = parseRequest(c.buf.Reader); err != nil {
		c.handleClientReadError(r, err, "parse client request")
		return nil
	}
	return r
}

func (c *clientConn) serve() {
	defer c.close()
	var r *Request
	var err error
	var h *Handler

	// Refer to implementation.md for the design choices on parsing the request<commit_msg>Close server connection when closing client connection.<commit_after>package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"net"
	"os"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"time"
)

// Lots of the code here are learnt from the http package

type Proxy struct {
	addr string // listen address
}

type connType byte

const (
	nilConn connType = iota
	directConn
	socksConn
)

type handlerState byte

const (
	hsConnected handlerState = iota
	hsResponsReceived
	hsStopped
)

type conn struct {
	net.Conn
	connType
}

type Handler struct {
	conn
	buf     *bufio.ReadWriter
	host    string
	state   handlerState
	lastUse time.Time
}

var one = make([]byte, 1)

func newHandler(c conn, host string) *Handler {
	return &Handler{
		conn: c,
		host: host,
		buf: bufio.NewReadWriter(bufio.NewReaderSize(c, bufSize),
			bufio.NewWriter(c)),
	}
}

type clientConn struct {
	buf      *bufio.ReadWriter
	net.Conn                     // connection to the proxy client
	handler  map[string]*Handler // request handler, host:port as key
}

var (
	errRetry    = errors.New("Retry")
	errPageSent = errors.New("Error page has sent")
)

func NewProxy(addr string) *Proxy {
	return &Proxy{addr: addr}
}

func (py *Proxy) Serve() {
	ln, err := net.Listen("tcp", py.addr)
	if err != nil {
		fmt.Println("Server creation failed:", err)
		os.Exit(1)
	}
	info.Println("COW proxy listening", py.addr)

	for {
		conn, err := ln.Accept()
		if err != nil {
			debug.Println("Client connection:", err)
			continue
		}
		if debug {
			debug.Println("New Client:", conn.RemoteAddr())
		}
		c := newClientConn(conn)
		go c.serve()
	}
}

// Explicitly specify buffer size to avoid unnecessary copy using
// bufio.Reader's Read
const bufSize = 4096

func newClientConn(rwc net.Conn) *clientConn {
	c := &clientConn{
		Conn:    rwc,
		handler: map[string]*Handler{},
		buf: bufio.NewReadWriter(bufio.NewReaderSize(rwc, bufSize),
			bufio.NewWriter(rwc)),
	}
	return c
}

func (c *clientConn) close() {
	for _, h := range c.handler {
		h.Close()
	}
	c.buf = nil
	c.Close()
	if debug {
		debug.Printf("Client %v connection closed\n", c.RemoteAddr())
	}
	c = nil
	runtime.GC()
}

func isSelfURL(h string) bool {
	return h == "" || h == selfURL127 || h == selfURLLH
}

func (c *clientConn) getRequest() (r *Request) {
	var err error
	if r, err = parseRequest(c.buf.Reader); err != nil {
		c.handleClientReadError(r, err, "parse client request")
		return nil
	}
	return r
}

func (c *clientConn) serve() {
	defer c.close()
	var r *Request
	var err error
	var h *Handler

	// Refer to implementation.md for the design choices on parsing the request
{'fraction_non_alphanumeric': 0.12604714591856614, 'fraction_numerical': 0.0035067212156633548, 'mean_word_length': 3.4760244115082823, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '3881605', 'n_tokens_mistral': 1931, 'n_tokens_neox': 1845, 'n_words': 542}