22 import Codec.Binary.UTF8.String
23 import qualified Data.ByteString.Lazy as Lazy (ByteString)
28 import Network.HTTP.Lucu
29 import Network.URI hiding (fragment)
30 import Subversion.Types
31 import System.FilePath.Posix
34 type PageName = String
36 type LanguageTag = String -- See RFC 3066: http://www.ietf.org/rfc/rfc3066.txt
37 type LanguageName = String -- i.e. "日本語"
42 redirName :: !PageName
43 , redirDest :: !PageName
44 , redirRevision :: !(Maybe RevNum)
45 , redirLastMod :: !UTCTime
49 , pageType :: !MIMEType
50 , pageLanguage :: !(Maybe LanguageTag)
51 , pageFileName :: !(Maybe String)
52 , pageIsTheme :: !Bool -- text/css 以外では無意味
53 , pageIsFeed :: !Bool -- text/x-rakka 以外では無意味
54 , pageIsLocked :: !Bool
55 , pageIsBoring :: !Bool
56 , pageIsBinary :: !Bool
57 , pageRevision :: !RevNum
58 , pageLastMod :: !UTCTime
59 , pageSummary :: !(Maybe String)
60 , pageOtherLang :: !(Map LanguageTag PageName)
61 , pageContent :: !Lazy.ByteString
66 -- UTF-8 に encode してから 0x20 - 0x7E の範圍を除いて URI escape する。
67 encodePageName :: PageName -> FilePath
68 encodePageName = escapeURIString isSafeChar . encodeString . fixPageName
70 fixPageName :: PageName -> PageName
71 fixPageName = (\ (x:xs) -> toUpper x : xs) . map (\ c -> if c == ' ' then '_' else c)
74 isSafeChar :: Char -> Bool
77 | isReserved c = False
78 | c > ' ' && c <= '~' = True
82 -- URI unescape して UTF-8 から decode する。
83 decodePageName :: FilePath -> PageName
84 decodePageName = decodeString . unEscapeString
87 encodeFragment :: String -> String
88 encodeFragment = escapeURIString isSafeChar . encodeString
91 pageFileName' :: Page -> String
93 = fromMaybe (defaultFileName (pageType page) (pageName page)) (pageFileName page)
96 defaultFileName :: MIMEType -> PageName -> String
97 defaultFileName pType pName
98 = let baseName = takeFileName pName
101 MIMEType "text" "x-rakka" _ -> baseName <.> "rakka"
102 MIMEType "text" "css" _ -> baseName <.> "css"
106 mkPageURI :: URI -> PageName -> URI
107 mkPageURI baseURI name
109 uriPath = foldl (</>) "/" [uriPath baseURI, encodePageName name ++ ".html"]
113 mkPageFragmentURI :: URI -> PageName -> String -> URI
114 mkPageFragmentURI baseURI name fragment
116 uriPath = foldl (</>) "/" [uriPath baseURI, encodePageName name ++ ".html"]
117 , uriFragment = ('#' : encodeFragment fragment)
121 mkFragmentURI :: String -> URI
122 mkFragmentURI fragment
124 uriFragment = ('#' : encodeFragment fragment)
128 mkObjectURI :: URI -> PageName -> URI
129 mkObjectURI baseURI name
130 = mkAuxiliaryURI baseURI ["object"] name
133 mkAuxiliaryURI :: URI -> [String] -> PageName -> URI
134 mkAuxiliaryURI baseURI basePath name
136 uriPath = foldl (</>) "/" ([uriPath baseURI] ++ basePath ++ [encodePageName name])
140 mkRakkaURI :: PageName -> URI
141 mkRakkaURI name = URI {
143 , uriAuthority = Nothing
144 , uriPath = encodePageName name