54 using(http_exchange.getResponseBody)(response.bytes.write_stream(_)) |
54 using(http_exchange.getResponseBody)(response.bytes.write_stream(_)) |
55 } |
55 } |
56 } |
56 } |
57 |
57 |
58 |
58 |
59 /* handler */ |
59 /* handler for request method */ |
60 |
|
61 class Handler private[HTTP](val root: String, val handler: HttpHandler) |
|
62 { |
|
63 override def toString: String = root |
|
64 } |
|
65 |
|
66 def handler(root: String, body: Exchange => Unit): Handler = |
|
67 new Handler(root, new HttpHandler { def handle(x: HttpExchange): Unit = body(new Exchange(x)) }) |
|
68 |
|
69 |
|
70 /* particular methods */ |
|
71 |
60 |
72 sealed case class Arg(method: String, uri: URI, request: Bytes) |
61 sealed case class Arg(method: String, uri: URI, request: Bytes) |
73 { |
62 { |
74 def decode_properties: Properties.T = |
63 def decode_properties: Properties.T = |
75 space_explode('&', request.text).map(s => |
64 space_explode('&', request.text).map(s => |
77 case List(a, b) => Url.decode(a) -> Url.decode(b) |
66 case List(a, b) => Url.decode(a) -> Url.decode(b) |
78 case _ => error("Malformed key-value pair in HTTP/POST: " + quote(s)) |
67 case _ => error("Malformed key-value pair in HTTP/POST: " + quote(s)) |
79 }) |
68 }) |
80 } |
69 } |
81 |
70 |
82 def method(name: String, root: String, body: Arg => Option[Response]): Handler = |
71 object Handler |
83 handler(root, http => |
72 { |
84 { |
73 def apply(root: String, body: Exchange => Unit): Handler = |
85 val request = http.read_request() |
74 new Handler(root, |
86 if (http.request_method == name) { |
75 new HttpHandler { def handle(x: HttpExchange): Unit = body(new Exchange(x)) }) |
87 val arg = Arg(name, http.request_uri, request) |
76 |
88 Exn.capture(body(arg)) match { |
77 def method(name: String, root: String, body: Arg => Option[Response]): Handler = |
89 case Exn.Res(Some(response)) => |
78 apply(root, http => |
90 http.write_response(200, response) |
79 { |
91 case Exn.Res(None) => |
80 val request = http.read_request() |
92 http.write_response(404, Response.empty) |
81 if (http.request_method == name) { |
93 case Exn.Exn(ERROR(msg)) => |
82 val arg = Arg(name, http.request_uri, request) |
94 http.write_response(500, Response.text(Output.error_message_text(msg))) |
83 Exn.capture(body(arg)) match { |
95 case Exn.Exn(exn) => throw exn |
84 case Exn.Res(Some(response)) => |
|
85 http.write_response(200, response) |
|
86 case Exn.Res(None) => |
|
87 http.write_response(404, Response.empty) |
|
88 case Exn.Exn(ERROR(msg)) => |
|
89 http.write_response(500, Response.text(Output.error_message_text(msg))) |
|
90 case Exn.Exn(exn) => throw exn |
|
91 } |
96 } |
92 } |
97 } |
93 else http.write_response(400, Response.empty) |
98 else http.write_response(400, Response.empty) |
94 }) |
99 }) |
|
100 |
95 |
101 def get(root: String, body: Arg => Option[Response]): Handler = method("GET", root, body) |
96 def get(root: String, body: Arg => Option[Response]): Handler = method("GET", root, body) |
102 def post(root: String, body: Arg => Option[Response]): Handler = method("POST", root, body) |
97 def post(root: String, body: Arg => Option[Response]): Handler = method("POST", root, body) |
|
98 } |
|
99 |
|
100 class Handler private(val root: String, val handler: HttpHandler) |
|
101 { |
|
102 override def toString: String = root |
|
103 } |
103 |
104 |
104 |
105 |
105 /* server */ |
106 /* server */ |
106 |
107 |
107 class Server private[HTTP](val http_server: HttpServer) |
108 class Server private[HTTP](val http_server: HttpServer) |
150 |
151 |
151 private lazy val html_fonts: List[Isabelle_Fonts.Entry] = |
152 private lazy val html_fonts: List[Isabelle_Fonts.Entry] = |
152 Isabelle_Fonts.fonts(hidden = true) |
153 Isabelle_Fonts.fonts(hidden = true) |
153 |
154 |
154 def fonts(root: String = "/fonts"): Handler = |
155 def fonts(root: String = "/fonts"): Handler = |
155 get(root, arg => |
156 Handler.get(root, arg => |
156 { |
157 { |
157 val uri_name = arg.uri.toString |
158 val uri_name = arg.uri.toString |
158 if (uri_name == root) { |
159 if (uri_name == root) { |
159 Some(Response.text(cat_lines(html_fonts.map(entry => entry.path.file_name)))) |
160 Some(Response.text(cat_lines(html_fonts.map(entry => entry.path.file_name)))) |
160 } |
161 } |