Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
JDK付属、Undertowを使ったGroovy&Clojure、Perlでの簡単なHTTPサーバ
#!/usr/bin/perl
## 使い方: $ perl simple-fork-httpd.pl [ポート番号(デフォルト8080)]
use strict;
use warnings;
use encoding 'utf8';
use Encode;
use Socket;
# 第1引数が、受付ポート番号
my $port;
if ($#ARGV >= 0) {
$port = $ARGV[0];
} else {
$port = 8080;
}
my $socket;
my $crlf = "\r\n";
socket($socket, PF_INET, SOCK_STREAM, 0) or die "Can't create Socket $!";
setsockopt($socket, SOL_SOCKET, SO_REUSEADDR, 1);
bind($socket, pack_sockaddr_in($port, INADDR_ANY)) or die "Can't bind Socket $!";
listen($socket, SOMAXCONN) or die "Can't listen Socket $!";
print '[' . get_time() . "] SimpleForkHttpd Server[$port]\n";
while (1) {
my $client_socket;
my $paddr = accept($client_socket, $socket);
my ($client_port, $client_iaddr) = unpack_sockaddr_in($paddr);
# my $client_hostname = gethostbyaddr($client_iaddr, AF_INET);
my $client_ip = inet_ntoa($client_iaddr);
print '[' . get_time() . "] Accept: Client[$client_ip:$client_port]\n";
my $pid = fork();
if ($pid == 0) {
# 子プロセス
$| = 1;
my $request = '';
while (my $line = <$client_socket>) {
$line =~ s/\r?\n$//;
$request .= $line . $crlf;
if ($line eq '') {
last;
}
}
# print '[' . get_time() . "] Client[$client_ip:$client_port] RequestDump\n$request\n";
my $headers = get_headers() . $crlf;
print $client_socket $headers;
my $body = get_body() . $crlf;
print $client_socket encode('utf-8', $body);
close($client_socket);
exit;
}
else {
# 親プロセス
}
}
close($socket);
sub get_headers {
my $headers = <<HEADERS;
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
X-Dummy-Header: Value
HEADERS
return $headers;
}
sub get_body {
my $body = <<BODY;
<html>
<header><title>タイトル</title><header>
<body>本文</body>
</html>
BODY
return $body;
}
sub get_time {
my ($sec, $min, $hour, $day, $mon, $year) = localtime();
return sprintf("%04D/%02d/%02d %02d:%02d:%02d", $year + 1900, $mon + 1,
$day, $hour, $min, $sec);
}
;; 使い方: $ lein exec simple-jdk-httpd.clj [ポート番号(デフォルト8080)]
(require '[leiningen.exec :as exec])
(ns simple-jdk-httpd
(:import (java.net InetSocketAddress)
(java.nio.charset StandardCharsets)
(java.util Date)
(java.util.concurrent Executors)
(com.sun.net.httpserver HttpHandler HttpServer)))
(defn response-handler [exchange]
(println (format "[%s] Accept: Client[%s], Url[%s]"
(Date.)
(. exchange getRemoteAddress)
(. exchange getRequestURI)))
(try
(let [body-text (-> (reduce #(str %1 (System/lineSeparator) %2)
["<html>"
"<header><title>タイトル</title></header>"
"<body>本文</body>"
"</html>"
""])
(.getBytes (StandardCharsets/UTF_8)))]
(doto (. exchange getResponseHeaders)
;; 追加ヘッダは先に書くこと
(.add "Content-Type" "text/html; charset=UTF-8")
(.add "X-Dummy-Header" "Value"))
(. exchange sendResponseHeaders 200 (count body-text))
(with-open [stream (. exchange getResponseBody)]
(. stream write body-text)))
(catch Exception e (. e printStackTrace))))
(let [port (if (> (count *command-line-args*) 1)
;; 最初の引数には、スクリプト名が入っているため
(Integer/parseInt (second *command-line-args*))
8080)
server (HttpServer/create (InetSocketAddress. port) 0)]
(doto server
(.setExecutor (Executors/newCachedThreadPool))
(.createContext "/"
(proxy [HttpHandler] []
(handle [exchange] (response-handler exchange))))
(.start))
(println (format "[%s] SimpleJdkHttpd Startup[%s]" (Date.) (. server getAddress)))
;; EnterかCtrl-cを入力されるまで、待ち合わせ
(read-line))
// 使い方: $ groovy simple-jdk-httpd.groovy [ポート番号(デフォルト8080)]
import java.nio.charset.StandardCharsets
import java.util.concurrent.Executors
import com.sun.net.httpserver.HttpHandler
import com.sun.net.httpserver.HttpServer
def responseHandler = { exchange ->
println("[${new Date()}] Accept: Client[$exchange.remoteAddress], Url[$exchange.requestURI]")
def bodyText = """|<html>
|<header><title>タイトル</title></header>
|<body>本文</body>
|</html>
|""".stripMargin().getBytes(StandardCharsets.UTF_8)
try {
// 追加ヘッダは先に書くこと
exchange.responseHeaders.with {
add("Content-Type", "text/html; charset=UTF-8")
add("X-Dummy-Header", "Value")
}
exchange.sendResponseHeaders(200, bodyText.size())
exchange.responseBody.withStream { it.write(bodyText) }
} catch (e) {
e.printStackTrace()
}
}
def server =
HttpServer.create(new InetSocketAddress(args.length > 0 ? args[0].toInteger() : 8080), 0)
server.executor = Executors.newCachedThreadPool()
server.createContext("/", responseHandler as HttpHandler)
server.start()
println("[${new Date()}] SimpleJdkHttpd Startup[${server.address}]")
;; 使い方: $ lein exec simple-undertow-httpd.clj [ポート番号(デフォルト8080)]
(require '[leiningen.exec :as exec])
(exec/deps '[[io.undertow/undertow-core "1.0.5.Final"]])
(ns simple-undertow-httpd
(:import (java.util Date)
(io.undertow Undertow)
(io.undertow.server HttpHandler)
(io.undertow.util Headers HttpString)))
(defn safe-handler [func]
(fn [exchange]
(try
(func exchange)
(catch Exception e (. e printStackTrace)))))
(defn acceptor [exchange]
(println (format "[%s] Accept: Client[%s], Url[%s]"
(Date.)
(. exchange getSourceAddress)
(. exchange getRequestURI)))
exchange)
(defn header [exchange]
(doto (. exchange getResponseHeaders)
(.put (Headers/CONTENT_TYPE) "text/html; charset=UTF8")
(.put (HttpString. "X-Dummy-Header") "Value"))
exchange)
(defn body [exchange]
(let [body-text (reduce #(str %1 (System/lineSeparator) %2)
["<html>"
"<header><title>タイトル</title></header>"
"<body>本文</body>"
"</html>"
""])]
(. (.. exchange getResponseSender) send body-text))
exchange)
(def response-handlers [acceptor header body])
(def handler (safe-handler (apply comp (reverse response-handlers))))
(let [host "localhost"
port (if (> (count *command-line-args*) 1)
;; 最初の引数には、スクリプト名が入っているため
(Integer/parseInt (second *command-line-args*))
8080)
server (-> (Undertow/builder)
(.addListener port host)
(.setHandler (proxy [HttpHandler] []
(handleRequest [exchange]
(handler exchange))))
(.build))]
(. server start)
(println (format "[%s] SimpleUndertowHttpd Startup[%s:%d]" (Date.) host port))
;; EnterかCtrl-cを入力されるまで、待ち合わせ
(read-line))
@Grab('io.undertow:undertow-core:1.0.5.Final')
import io.undertow.Undertow
import io.undertow.server.HttpHandler
import io.undertow.util.Headers
import io.undertow.util.HttpString
def safeHandler = { clos ->
{ exchange ->
try {
clos.call(exchange)
} catch (e) {
e.printStackTrace()
}
}
}
def acceptor = { exchange ->
println("[${new Date()}] Accept: Client[$exchange.sourceAddress], Url[$exchange.requestURI]")
exchange
}
def header = { exchange ->
exchange.responseHeaders.with {
put(Headers.CONTENT_TYPE, "text/html; charset=UTF-8")
put(new HttpString("X-Dummy-Header"), "Value")
}
exchange
}
def body = { exchange ->
def bodyText = """|<html>
|<header><title>タイトル</title></header>
|<body>本文</body>
|</html>
|""".stripMargin()
exchange.responseSender.send(bodyText)
exchange
}
def host = "localhost"
def port = args.length > 0 ? args[0].toInteger() : 8080
// 左から右に向かって合成する
def responseHandlers = [acceptor, header, body]
// 合成したClosureを、safeHandlerで包む
def handler =
safeHandler(responseHandlers.tail().inject(responseHandlers.head()) { acc, c -> acc >> c })
def server =
Undertow
.builder()
.addListener(port, host)
.setHandler(handler as HttpHandler)
.build()
server.start()
println("[${new Date()}] SimpleUndertowHttpd Startup[$host:$port]")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment