#!/usr/bin/env bash
# Copyright 2016 Luke Shumaker
# License: WTFPLv2

# Dependencies:
# - bash
# - sed
# - socat
# - date -R

server="${0##*/}"

OK() {
	printf '%s\r\n' \
	       'HTTP/1.1 200 OK' \
	       "Server: $server" \
	       "Date: $(date -R)" \
	       ''
}

Forbidden() {
	body='403 Forbidden'
	printf '%s\r\n' \
	       'HTTP/1.1 403 Forbidden' \
	       "Server: $server" \
	       "Date: $(date -R)" \
	       'Allow: CONNECT' \
	       "Content-Length: ${#body}" \
	       ''
	printf '%s' "$body"
}

MethodNotAllowed() {
	body='405 Method Not Allowed'
	printf '%s\r\n' \
	       'HTTP/1.1 405 Method Not Allowed' \
	       "Server: $server" \
	       "Date: $(date -R)" \
	       'Allow: CONNECT' \
	       "Content-Length: ${#body}" \
	       ''
	printf '%s' "$body"
}

ProxyAuthenticationRequired() {
	body='407 Proxy Authentication Required'
	printf '%s\r\n' \
	       'HTTP/1.1 407 Proxy Authentication Required' \
	       "Server: $server" \
	       "Date: $(date -R)" \
	       "Proxy-Authenticate: $(echo $(declare -F|sed -n 's/^declare -f authenticate_//p')|sed 's/ /, /g')" \
	       "Content-Length: ${#body}" \
	       ''
	printf '%s' "$body"
}

InternalServerError() {
	body='500 Internal Server Error'
	printf '%s\r\n' \
	       'HTTP/1.1 500 Internal Server Error' \
	       "Server: $server" \
	       "Date: $(date -R)" \
	       "Content-Length: ${#body}" \
	       ''
	printf '%s' "$body"
}

checkdest() {
	true
}

worker() {
	local conffile
	for conffile in /etc/httpconnectd/*.conf; do
		if ! source "$conffile"; then
			InternalServerError
		fi
	done
	local method dest version
	read -r method dest version || exit 1
	if [[ "$method" != CONNECT ]]; then
		MethodNotAllowed
		return 0
	fi
	local authenticated=false
	local line
	while read -r line; do
		line="${line%$'\r'}"
		case "${line,,}" in
			proxy-authorization:*)
				local scheme authparams
				read -r scheme authparams <<<"${line#*:}"
				scheme=${scheme,,}
				if authenticate_${scheme} "$authparams" 1>&2; then
					authenticated=true
				fi
				;;
			'')
				if ! $authenticated; then
					ProxyAuthenticationRequired
					return 0
				fi
				if ! checkdest "$dest"; then
					Forbidden
					return 0
				fi
				OK
				exec socat STDIO TCP-CONNECT:"$dest"
				;;
		esac
	done
	exit 1
}

while worker "$@"; do :; done
