diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..e909cef --- /dev/null +++ b/build.sbt @@ -0,0 +1,7 @@ +name := "ScaProxy" + +version := "0.1" + +scalaVersion := "2.12.8" + +libraryDependencies += "org.ekrich" %% "sconfig" % "0.7.0" \ No newline at end of file diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf new file mode 100644 index 0000000..378c410 --- /dev/null +++ b/src/main/resources/application.conf @@ -0,0 +1,2 @@ +scaproxy.host = "localhost" +scaproxy.port = 9090 \ No newline at end of file diff --git a/src/main/scala/ru/bvn13/scaproxy/config/Config.scala b/src/main/scala/ru/bvn13/scaproxy/config/Config.scala new file mode 100644 index 0000000..ff06975 --- /dev/null +++ b/src/main/scala/ru/bvn13/scaproxy/config/Config.scala @@ -0,0 +1,14 @@ +package ru.bvn13.scaproxy.config + +import org.ekrich.config.{Config, ConfigFactory} + +object Config { + + private val config: Config = ConfigFactory.systemEnvironment() + .withFallback(ConfigFactory.parseResources("application.conf")) + + def host:String = config.getString("scaproxy.host") + + def port:Int = config.getInt("scaproxy.port") + +} diff --git a/src/main/scala/ru/bvn13/scaproxy/engine/ClientListener.scala b/src/main/scala/ru/bvn13/scaproxy/engine/ClientListener.scala new file mode 100644 index 0000000..487a51a --- /dev/null +++ b/src/main/scala/ru/bvn13/scaproxy/engine/ClientListener.scala @@ -0,0 +1,47 @@ +package ru.bvn13.scaproxy.engine + + +import java.io.{BufferedReader, InputStreamReader} +import java.net.{InetAddress, Socket} +import java.util.concurrent.{ExecutorService, Executors} +import java.util.regex.{Matcher, Pattern} + +case class ClientListener(clientSocket: Socket) extends Runnable { + + private val RE_HOST = Pattern.compile("^Host: (\\S)+:(\\d)*") + + private var buffer: List[String] = List() + + private var outgoingTunnel: SocketTunnel = ??? + private var incomingTunnel: SocketTunnel = ??? + + private val executorService: ExecutorService = Executors.newFixedThreadPool(2) + + override def run(): Unit = { + + val clientStream = new BufferedReader(new InputStreamReader(clientSocket.getInputStream)) + var line = clientStream.readLine + + while (line != null && !line.isEmpty) { + buffer = line :: buffer + } + + if (buffer.length >= 2) { + val matcher: Matcher = RE_HOST.matcher(buffer(2)) + if (matcher.matches) { + val host:String = matcher.group(1) + val port:String = if (matcher.groupCount > 2) matcher.group(2) else "80" + + val remoteSocket: Socket = new Socket(InetAddress.getByName(host), port.toInt) + + outgoingTunnel = SocketTunnel(sender = clientSocket, receiver = remoteSocket) + outgoingTunnel.initialBuffer = buffer + incomingTunnel = SocketTunnel(sender = remoteSocket, receiver = clientSocket) + + executorService.execute(outgoingTunnel) + executorService.execute(incomingTunnel) + } + } + + } +} diff --git a/src/main/scala/ru/bvn13/scaproxy/engine/ProxyServer.scala b/src/main/scala/ru/bvn13/scaproxy/engine/ProxyServer.scala index 0386d48..d56f299 100644 --- a/src/main/scala/ru/bvn13/scaproxy/engine/ProxyServer.scala +++ b/src/main/scala/ru/bvn13/scaproxy/engine/ProxyServer.scala @@ -1,10 +1,44 @@ package ru.bvn13.scaproxy.engine +import java.io.IOException +import java.net.{InetAddress, ServerSocket, Socket} +import java.util.concurrent.{ExecutorService, Executors} + +import ru.bvn13.scaproxy.config.Config + class ProxyServer { - def start = { + private val executorService: ExecutorService = Executors.newCachedThreadPool + + private var clients: List[ClientListener] = List() + + def start():Unit = { println("ScaProxy started") + println("listening "+Config.host+":"+Config.port) + + executorService.execute(mainThread) + + } + + def mainThread:Runnable = () => { + + val serverSocket: ServerSocket = new ServerSocket(Config.port, 0, InetAddress.getByName(Config.host)) + + try { + + while (!serverSocket.isClosed) { + val socket: Socket = serverSocket.accept() + val clientListener: ClientListener = ClientListener(socket) + executorService.execute(clientListener) + clients = clientListener :: clients + } + + } catch { + case e: IOException => e.printStackTrace() + } finally { + serverSocket.close() + } } diff --git a/src/main/scala/ru/bvn13/scaproxy/engine/SocketTunnel.scala b/src/main/scala/ru/bvn13/scaproxy/engine/SocketTunnel.scala new file mode 100644 index 0000000..63f17e5 --- /dev/null +++ b/src/main/scala/ru/bvn13/scaproxy/engine/SocketTunnel.scala @@ -0,0 +1,20 @@ +package ru.bvn13.scaproxy.engine + +import java.io.{InputStreamReader, OutputStreamWriter} +import java.net.Socket + +case class SocketTunnel(sender: Socket, receiver: Socket) extends Runnable { + + private val senderStream: InputStreamReader = new InputStreamReader(sender.getInputStream) + + private val receiverStream: OutputStreamWriter = new OutputStreamWriter(receiver.getOutputStream) + + var initialBuffer: List[String] = List() + + override def run(): Unit = { + + + + } +} +