<commit_before>// $begin{copyright}
// 
// This file is part of WebSharper
// 
// Copyright (c) 2008-2012 IntelliFactory
// 
// GNU Affero General Public License Usage
// WebSharper is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License, version 3, as published
// by the Free Software Foundation.
//
// WebSharper is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
// for more details at <http://www.gnu.org/licenses/>.
//
// If you are unsure which license is appropriate for your use, please contact
// IntelliFactory at http://intellifactory.com/contact.
//
// $end{copyright}

namespace IntelliFactory.WebSharper.Sitelets

open System
open System.Collections.Generic
open System.Configuration
open System.Diagnostics
open System.IO
open System.Reflection
open System.Web
open System.Web.Hosting

module internal SiteLoading =

    let TryLoadSite (assembly: Assembly) =
        let aT = typeof<WebsiteAttribute>
        match System.Attribute.GetCustomAttribute(assembly, aT) with
        | :? WebsiteAttribute as attr ->
            attr.Run () |> Some
        |_ -> None

    let LoadFromAssemblies () =
        Timed "Initialized sitelets" <| fun () ->
            let assemblies =
                System.Web.Compilation.BuildManager.GetReferencedAssemblies()
                |> Seq.cast<System.Reflection.Assembly>
            let pairs = Seq.choose TryLoadSite assemblies
            let sitelets = Seq.map fst pairs
            let actions = Seq.map snd pairs
            (Sitelet.Sum sitelets, Seq.concat actions)

module private WebUtils =

    let currentSite =
        lazy fst (SiteLoading.LoadFromAssemblies())

    /// Converts ASP.NET requests to Sitelet requests.
    let convertRequest (ctx: HttpContext) : Http.Request =
        let METHOD = function
            | "CONNECT" -> Http.Method.Connect
            | "DELETE" -> Http.Method.Delete
            | "GET" -> Http.Method.Get
            | "HEAD" -> Http.Method.Head
            | "OPTIONS" -> Http.Method.Options
            | "POST" -> Http.Method.Post
            | "PUT" -> Http.Method.Put
            | "TRACE" -> Http.Method.Trace
            | rest -> Http.Method.Custom rest
        let req = ctx.Request
        let resp = ctx.Response
        let headers =
            seq {
                for key in req.Headers.AllKeys do
                    yield Http.Header.Custom key req.Headers.[key]
            }
        // app.Context.Request.Cookies
        let parameters =
            seq {
                for p in ctx.Request.Params.AllKeys do
                    yield (p, req.[p])
            }
        {
            Method = METHOD ctx.Request.HttpMethod
            Uri = req.Url
            Headers = headers
            Body = resp.OutputStream
            Post = new Http.ParameterCollection(req.Form)
            Get  = new Http.ParameterCollection(req.QueryString)
            Cookies = req.Cookies
            ServerVariables = new Http.ParameterCollection(req.ServerVariables)
            Files =
                let fs = req.Files
                seq {
                    for k in fs.Keys do
                        yield fs.[k]
                }
        }

    /// Normalizes the application path.
    let appPath (req: HttpRequest) =
        if req.ApplicationPath = "/"
        then ""
        else req.ApplicationPath

    /// Gets the sitelet for a given context.
    let getSitelet (site: Sitelet<obj>) (ctx: HttpContext) =
        let req = ctx.Request
        let appPath = appPath ctx.Request
        Sitelet.Shift appPath site

    /// Constructs the sitelet context object.
    let getContext (site: Sitelet<obj>) (req: HttpRequest) (request: Http.Request) : Context<obj> =
        let appPath = appPath req
        {
            ApplicationPath = appPath
            ResolveUrl = fun url ->
                if url.StartsWith ("~") then
                    appPath + url.Substring(1)
                else
                    url
            Json = ResourceContext.SharedJson()
            Link = fun action ->
                match site.Router.Link action  with
                | Some loc -> loc.ToString()
                | None -> failwith "Failed to link to action"
            Metadata = ResourceContext.MetaData()
            ResourceContext = ResourceContext.ResourceContext appPath
            Request = request
        }

    /// Writes a response.
    let respond (site: Sitelet<obj>) (ctx: HttpContext) (req: Http.Request) (action: obj) =
        // Create a context
        let context = getContext site ctx.Request req
        // Handle action
        let response =
            (site.Controller.Handle action, context)
            ||> Content.ToResponse
        let resp = ctx.Response
        resp.Status <- response.Status.ToString()
        for header in response.Headers do
            resp.AddHeader(header.Name, header.Value)
        response.WriteBody resp.OutputStream
        resp.End()

/// The ISS handler for WebSharper applications.
[<Sealed>]
type HttpHandler(request: Http.Request, action: obj) =
    interface SessionState.IRequiresSessionState
    interface IHttpHandler with
        member this.IsReusable = false
        member this.ProcessRequest(ctx) =
            WebUtils.respond WebUtils.currentSite.Value ctx request action

/// IIS module, processing the URLs and serving the pages.
type HttpModule() =
    interface IHttpModule with
        member this.Init app =
            app.add_PostAuthorizeRequest(new EventHandler(fun x e ->
                let app = (x :?> HttpApplication)
                let ctx = app.Context
                let sitelet = WebUtils.getSitelet WebUtils.currentSite.Value ctx
                let request = WebUtils.convertRequest ctx
                match sitelet.Router.Route(request) with
                | None -> ()
                | Some action -> ctx.RemapHandler(HttpHandler(request, action))))
        member this.Dispose() = ()
<commit_msg>Fix sitelets on webdev server.<commit_after>// $begin{copyright}
// 
// This file is part of WebSharper
// 
// Copyright (c) 2008-2012 IntelliFactory
// 
// GNU Affero General Public License Usage
// WebSharper is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License, version 3, as published
// by the Free Software Foundation.
//
// WebSharper is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
// for more details at <http://www.gnu.org/licenses/>.
//
// If you are unsure which license is appropriate for your use, please contact
// IntelliFactory at http://intellifactory.com/contact.
//
// $end{copyright}

namespace IntelliFactory.WebSharper.Sitelets

open System
open System.Collections.Generic
open System.Configuration
open System.Diagnostics
open System.IO
open System.Reflection
open System.Web
open System.Web.Hosting

module internal SiteLoading =

    let TryLoadSite (assembly: Assembly) =
        let aT = typeof<WebsiteAttribute>
        match System.Attribute.GetCustomAttribute(assembly, aT) with
        | :? WebsiteAttribute as attr ->
            attr.Run () |> Some
        |_ -> None

    let LoadFromAssemblies () =
        Timed "Initialized sitelets" <| fun () ->
            let assemblies =
                System.Web.Compilation.BuildManager.GetReferencedAssemblies()
                |> Seq.cast<System.Reflection.Assembly>
            let pairs = Seq.choose TryLoadSite assemblies
            let sitelets = Seq.map fst pairs
            let actions = Seq.map snd pairs
            (Sitelet.Sum sitelets, Seq.concat actions)

module private WebUtils =

    let currentSite =
        lazy fst (SiteLoading.LoadFromAssemblies())

    /// Converts ASP.NET requests to Sitelet requests.
    let convertRequest (ctx: HttpContext) : Http.Request =
        let METHOD = function
            | "CONNECT" -> Http.Method.Connect
            | "DELETE" -> Http.Method.Delete
            | "GET" -> Http.Method.Get
            | "HEAD" -> Http.Method.Head
            | "OPTIONS" -> Http.Method.Options
            | "POST" -> Http.Method.Post
            | "PUT" -> Http.Method.Put
            | "TRACE" -> Http.Method.Trace
            | rest -> Http.Method.Custom rest
        let req = ctx.Request
        let resp = ctx.Response
        let headers =
            seq {
                for key in req.Headers.AllKeys do
                    yield Http.Header.Custom key req.Headers.[key]
            }
        // app.Context.Request.Cookies
        let parameters =
            seq {
                for p in ctx.Request.Params.AllKeys do
                    yield (p, req.[p])
            }
        {
            Method = METHOD ctx.Request.HttpMethod
            Uri = req.Url
            Headers = headers
            Body = resp.OutputStream
            Post = new Http.ParameterCollection(req.Form)
            Get  = new Http.ParameterCollection(req.QueryString)
            Cookies = req.Cookies
            ServerVariables = new Http.ParameterCollection(req.ServerVariables)
            Files =
                let fs = req.Files
                seq {
                    for k in fs.Keys do
                        yield fs.[k]
                }
        }

    /// Normalizes the application path.
    let appPath (req: HttpRequest) =
        if req.ApplicationPath = "/"
        then ""
        else req.ApplicationPath

    /// Gets the sitelet for a given context.
    let getSitelet (site: Sitelet<obj>) (ctx: HttpContext) =
        let req = ctx.Request
        let appPath = appPath ctx.Request
        Sitelet.Shift appPath site

    /// Constructs the sitelet context object.
    let getContext (site: Sitelet<obj>) (req: HttpRequest) (request: Http.Request) : Context<obj> =
        let appPath = appPath req
        {
            ApplicationPath = appPath
            ResolveUrl = fun url ->
                if url.StartsWith ("~") then
                    appPath + url.Substring(1)
                else
                    url
            Json = ResourceContext.SharedJson()
            Link = fun action ->
                match site.Router.Link action  with
                | Some loc -> loc.ToString()
                | None -> failwith "Failed to link to action"
            Metadata = ResourceContext.MetaData()
            ResourceContext = ResourceContext.ResourceContext appPath
            Request = request
        }

    /// Writes a response.
    let respond (site: Sitelet<obj>) (ctx: HttpContext) (req: Http.Request) (action: obj) =
        // Create a context
        let context = getContext site ctx.Request req
        // Handle action
        let response =
            (site.Controller.Handle action, context)
            ||> Content.ToResponse
        let resp = ctx.Response
        resp.Status <- response.Status.ToString()
        for header in response.Headers do
            resp.AddHeader(header.Name, header.Value)
        response.WriteBody resp.OutputStream
        resp.End()

/// The ISS handler for WebSharper applications.
[<Sealed>]
type HttpHandler(request: Http.Request, action: obj) =
    interface SessionState.IRequiresSessionState
    interface IHttpHandler with
        member this.IsReusable = false
        member this.ProcessRequest(ctx) = this.ProcessRequest(ctx)
    member this.ProcessRequest(ctx) =
        WebUtils.respond WebUtils.currentSite.Value ctx request action

/// IIS module, processing the URLs and serving the pages.
type HttpModule() =
    interface IHttpModule with
        member this.Init app =
            app.add_PostAuthorizeRequest(new EventHandler(fun x e ->
                let app = (x :?> HttpApplication)
                let ctx = app.Context
                let sitelet = WebUtils.getSitelet WebUtils.currentSite.Value ctx
                let request = WebUtils.convertRequest ctx
                if HttpRuntime.UsingIntegratedPipeline then
                    match sitelet.Router.Route(request) with
                    | None -> ()
                    | Some action -> ctx.RemapHandler(HttpHandler(request, action))
                else
                    match sitelet.Router.Route(request) with
                    | None -> ()
                    | Some action -> HttpHandler(request, action).ProcessRequest(ctx)))
        member this.Dispose() = ()

{'fraction_non_alphanumeric': 0.08409632992228976, 'fraction_numerical': 0.001538816649996153, 'mean_word_length': 1.7255189767246801, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4325214', 'n_tokens_mistral': 3523, 'n_tokens_neox': 3200, 'n_words': 991}