Skip to content

Instantly share code, notes, and snippets.

@igm
Created June 15, 2012 11:53
Show Gist options
  • Save igm/2936086 to your computer and use it in GitHub Desktop.
Save igm/2936086 to your computer and use it in GitHub Desktop.
Simple HTTP Server in Scala & Java 7 (async I/O)
import java.lang.Character.{ LETTER_NUMBER => CR,LINE_SEPARATOR => LF }
import java.net.InetSocketAddress
import java.nio.channels.AsynchronousChannelGroup._
import java.nio.channels.AsynchronousServerSocketChannel._
import java.nio.channels.{ AsynchronousSocketChannel => ASC }
import java.nio.channels.CompletionHandler
import java.nio.ByteBuffer._
import java.util.concurrent.Executors._
import scala.annotation.implicitNotFound
import scala.collection.mutable.ListBuffer
object HttpServer extends App {
val channelGroup = withFixedThreadPool(1, defaultThreadFactory());
val listenChannel = open(channelGroup).bind(new InetSocketAddress(8000));
while (true) MyHttpProcess(listenChannel.accept().get())();
}
case class MyHttpProcess(ch: ASC) {
val buf = allocate(1024); buf.flip()
implicit def fn2CH(fn: Int => Unit) = new CompletionHandler[Integer, Void]() {
def completed(res: Integer, _2: Void): Unit = fn(res)
def failed(_1: Throwable, _2: Void) = throw new RuntimeException(_1)
}
def apply() = readLine { request_line => readHeader { header => ch.write(wrap(html), null, (res: Int) => ch.close()) } }
def readHeader(fn: List[String] => Unit, lines: ListBuffer[String] = new ListBuffer): Unit = readLine {
case "" => fn(lines.toList)
case any => readHeader(fn, lines += any);
}
def readLine(fn: String => Unit, sb: StringBuilder = new StringBuilder): Unit = readChar {
case LF => readChar { case CR => fn(sb.toString) }
case CR => fn(sb.toString);
case any => readLine(fn, sb += any)
}
def readChar(fn: Char => Unit) = buf.hasRemaining() match {
case true => fn(buf.get().toChar);
case _ =>
buf.clear();
ch.read(buf, null, (res: Int) => if (res != -1) { buf.flip(); fn(buf.get().toChar) } else ch.close())
}
val html = """
HTTP/1.1 200
Client
Date: Tue, 24 Apr 2012 10:10:51 GMT
Content-Type: text/html; charset=ISO-8859-1
<h1>Hello World</h2>""".getBytes
}
@igm
Copy link
Author

igm commented Jun 15, 2012

ab -c100 -n100000 "http://localhost:8000/"
Server Software:
Server Hostname: localhost
Server Port: 8000
Document Path: /
Document Length: 20 bytes
Concurrency Level: 100
Time taken for tests: 4.953 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 12200000 bytes
HTML transferred: 2000000 bytes
Requests per second: 20190.79 #/sec
Time per request: 4.953 ms
Time per request: 0.050 [ms](mean, across all concurrent requests)
Transfer rate: 2405.54 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 3 35.5 1 1002
Processing: 0 2 1.8 2 235
Waiting: 0 2 1.8 1 234
Total: 0 5 35.6 3 1005

@joeatbayes
Copy link

You did not include a license for this code. Do you mind if I make a derivative and republish

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment