21 import Data.ByteString.Base (LazyByteString)
22 import qualified Data.ByteString.Char8 as C8
25 import Data.Encoding.UTF8
28 import Network.HTTP.Lucu
30 import Subversion.Types
31 import System.FilePath.Posix
35 type PageName = String
37 type LanguageTag = String -- See RFC 3066: http://www.ietf.org/rfc/rfc3066.txt
38 type LanguageName = String -- i.e. "日本語"
43 redirName :: !PageName
44 , redirDest :: !PageName
45 , redirRevision :: !(Maybe RevNum)
46 , redirLastMod :: !CalendarTime
50 , pageType :: !MIMEType
51 , pageLanguage :: !(Maybe LanguageTag)
52 , pageFileName :: !(Maybe String)
53 , pageIsTheme :: !Bool -- text/css 以外では無意味
54 , pageIsFeed :: !Bool -- text/x-rakka 以外では無意味
55 , pageIsLocked :: !Bool
56 , pageIsBoring :: !Bool
57 , pageIsBinary :: !Bool
58 , pageRevision :: !RevNum
59 , pageLastMod :: !CalendarTime
60 , pageSummary :: !(Maybe String)
61 , pageOtherLang :: !(Map LanguageTag PageName)
62 , pageContent :: !LazyByteString
66 -- UTF-8 に encode してから 0x20 - 0x7E の範圍を除いて URI escape する。
67 encodePageName :: PageName -> FilePath
68 encodePageName = escapeURIString isSafeChar . C8.unpack . encode UTF8 . 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 = decode UTF8 . C8.pack . unEscapeString
87 encodeFragment :: String -> String
88 encodeFragment = escapeURIString isSafeChar . C8.unpack . encode UTF8
91 pageFileName' :: Page -> String
92 pageFileName' page = fromMaybe (defaultFileName page) (pageFileName page)
95 defaultFileName :: Page -> String
97 = let baseName = takeFileName (pageName page)
100 MIMEType "text" "x-rakka" _ -> baseName <.> "rakka"
101 MIMEType "text" "css" _ -> baseName <.> "css"
105 mkPageURI :: URI -> PageName -> URI
106 mkPageURI baseURI name
108 uriPath = foldl (</>) "/" [uriPath baseURI, encodePageName name ++ ".html"]
112 mkPageFragmentURI :: URI -> PageName -> String -> URI
113 mkPageFragmentURI baseURI name fragment
115 uriPath = foldl (</>) "/" [uriPath baseURI, encodePageName name ++ ".html"]
116 , uriFragment = ('#' : encodeFragment fragment)
120 mkFragmentURI :: String -> URI
121 mkFragmentURI fragment
123 uriFragment = ('#' : encodeFragment fragment)
127 mkObjectURI :: URI -> PageName -> URI
128 mkObjectURI baseURI name
129 = mkAuxiliaryURI baseURI ["object"] name
132 mkAuxiliaryURI :: URI -> [String] -> PageName -> URI
133 mkAuxiliaryURI baseURI basePath name
135 uriPath = foldl (</>) "/" ([uriPath baseURI] ++ basePath ++ [encodePageName name])
139 mkRakkaURI :: PageName -> URI
140 mkRakkaURI name = URI {
142 , uriAuthority = Nothing
143 , uriPath = encodePageName name