src/Pure/General/http.scala
changeset 73413 56c0a793cd8b
parent 73367 77ef8bef0593
child 73416 08aa4c1ed579
equal deleted inserted replaced
73412:83569d243671 73413:56c0a793cd8b
    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)
   136 
   137 
   137 
   138 
   138   /* welcome */
   139   /* welcome */
   139 
   140 
   140   val welcome: Handler =
   141   val welcome: Handler =
   141     get("/", arg =>
   142     Handler.get("/", arg =>
   142       if (arg.uri.toString == "/") {
   143       if (arg.uri.toString == "/") {
   143         val id = Isabelle_System.isabelle_id()
   144         val id = Isabelle_System.isabelle_id()
   144         Some(Response.text("Welcome to Isabelle/" + id + ": " + Distribution.version))
   145         Some(Response.text("Welcome to Isabelle/" + id + ": " + Distribution.version))
   145       }
   146       }
   146       else None)
   147       else None)
   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         }