JDK付属、Undertowを使ったGroovy&Clojure、Perlでの簡単なHTTPサーバ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 使い方: $ 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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 使い方: $ 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}]") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; 使い方: $ 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)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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