Kurose’s book exercises (labs) — HTTP Proxy Cache
These codes are implementations of the exercise described here: http://www.cs.uic.edu/~troy/spring05/cs450/mp1.html
HttpResponse
class HttpResponse(fromServer: DataInputStream) {
var version = ""
var status = 0
var statusLine = ""
var headers = ""
var body = new Array[Byte](Configs.MAX_OBJECT_SIZE)
var length = -1
try {
var line = fromServer.readLine
var gotStatusLine = false
while (line.length != 0) {
if (!gotStatusLine) {
statusLine = line
gotStatusLine = true
} else {
headers += line + Configs.CRLF
}
if (line.startsWith("Content-Length:") ||
line.startsWith("Content-length:")) {
val tmp = line.split(" ")
length = tmp(1).toInt
}
line = fromServer.readLine
}
} catch {
case e: IOException =>
println("Error reading headers from server: " + e)
}
try {
var bytesRead = 0
var buf = new Array[Byte](Configs.BUF_SIZE)
var loop = false
if (length == -1)
loop = true
breakable {
while (bytesRead < length || loop) {
val res = fromServer.read(buf, 0, Configs.BUF_SIZE)
if (res == 1)
break
var i = 0
while (i < res && (i + bytesRead) < Configs.MAX_OBJECT_SIZE) {
body(bytesRead + i) = buf(i)
i += 1
}
bytesRead += res
}
}
} catch {
case e: IOException =>
println("Error reading headers from body: " + e)
}
override def toString = {
val res = statusLine + Configs.CRLF + headers + Configs.CRLF
res
}
}
HttpRequest
class HttpRequest(from: BufferedReader) {
private var method = ""
private var URI = ""
private var version = ""
private var headers = ""
private var _host = ""
private var _port = Configs.HTTP_PORT
try {
val firstLine = from.readLine
val tmp = firstLine.split(" ")
method = tmp(0)
URI = tmp(1)
version = tmp(2)
} catch {
case e: IOException =>
println("Error reading request line: " + e)
}
println("URI:" + URI)
if (!(method equals "GET"))
println("Error: Method not GET")
try {
var line = from.readLine
while (line.length != 0) {
headers += line + Configs.CRLF
if (line startsWith "Host:") {
val tmp = line.split(" ")
if (tmp(1).indexOf(':') > 0) {
val tmp2 = tmp(1).split(":")
_host = tmp2(0)
_port = tmp2(1).toInt
} else {
_host = tmp(1)
_port = Configs.HTTP_PORT
}
}
}
} catch {
case e: IOException =>
println("Error reading from socket: " + e)
}
def host = _host
def port = _port
override def toString = {
var req = method + " " + URI + " " + version + Configs.CRLF
req += headers
req += "Connection: close" + Configs.CRLF + Configs.CRLF
req
}
}
ProxyCache
class ProxyCache(port: Int) {
var socket: ServerSocket = null.asInstanceOf[ServerSocket]
try {
socket = new ServerSocket(port)
} catch {
case e: IOException =>
println("Socket creation error: " + e)
exit(-1)
}
def handle(client: Socket) {
var server: Socket = null.asInstanceOf[Socket]
var request: HttpRequest = null.asInstanceOf[HttpRequest]
try {
val fromClient =
new BufferedReader(new InputStreamReader(client.getInputStream))
println("Reading request...")
request = new HttpRequest(fromClient)
println("Got request...")
} catch {
case e: IOException =>
println("Error reading request from client: " + e)
return
}
try {
server = new Socket(request.host, request.port)
val toServer = new DataOutputStream(server.getOutputStream)
toServer.writeBytes(request.toString)
} catch {
case e: UnknownHostException =>
println("Unknown host: " + request.host)
println(e)
return
case e: IOException =>
println("Error writing request to server: " + e)
return
}
try {
val fromServer = new DataInputStream(server.getInputStream)
val response = new HttpResponse(fromServer)
val toClient = new DataOutputStream(client.getOutputStream)
toClient.writeBytes(response.toString)
toClient.write(response.body)
client.close
server.close
} catch {
case e: IOException =>
println("Error writing response to client: " + e)
}
}
}
Configs
object Configs {
val CRLF = "\r\n"
val HTTP_PORT = 8080
val BUF_SIZE = 8192
val MAX_OBJECT_SIZE = 100000
}
The Main
object Main {
def main(args: Array[String]) {
val myPort = args(0).toInt
val proxyCache = new ProxyCache(myPort)
println("Cache started... Port: " + myPort)
while (true) {
try {
val client = proxyCache.socket.accept
println("Got connection " + client)
proxyCache.handle(client)
} catch {
case e: IOException =>
println("Error reading request from client: " + e)
}
}
}
}
These codes can be found here: ProxyCache.scala