http.go (view raw)
1package main
2
3import (
4 "git.sr.ht/~adnano/gmi"
5 "html/template"
6 "log"
7 "net/http"
8 "os"
9 "path"
10 "strings"
11)
12
13var t *template.Template
14
15// TODO somewhat better error handling
16const InternalServerErrorMsg = "500: Internal Server Error"
17
18func renderError(w http.ResponseWriter, errorMsg string, statusCode int) { // TODO think about pointers
19 data := struct{ ErrorMsg string }{errorMsg}
20 err := t.ExecuteTemplate(w, "error.html", data)
21 if err != nil { // shouldn't happen probably
22 http.Error(w, errorMsg, statusCode)
23 }
24}
25
26func indexHandler(w http.ResponseWriter, r *http.Request) {
27 indexFiles, err := getIndexFiles()
28 if err != nil {
29 log.Println(err)
30 renderError(w, InternalServerErrorMsg, 500)
31 return
32 }
33 allUsers, err := getUsers()
34 if err != nil {
35 log.Println(err)
36 renderError(w, InternalServerErrorMsg, 500)
37 return
38 }
39 data := struct {
40 Domain string
41 PageTitle string
42 Files []*File
43 Users []string
44 }{c.RootDomain, c.SiteTitle, indexFiles, allUsers}
45 err = t.ExecuteTemplate(w, "index.html", data)
46 if err != nil {
47 log.Println(err)
48 renderError(w, InternalServerErrorMsg, 500)
49 return
50 }
51
52}
53
54func editFileHandler(w http.ResponseWriter, r *http.Request) {
55 // read file content. create if dne
56 // authUser := "alex"
57 data := struct {
58 FileName string
59 FileText string
60 PageTitle string
61 }{"filename", "filetext", c.SiteTitle}
62 err := t.ExecuteTemplate(w, "edit_file.html", data)
63 if err != nil {
64 log.Println(err)
65 renderError(w, InternalServerErrorMsg, 500)
66 return
67 }
68}
69
70func mySiteHandler(w http.ResponseWriter, r *http.Request) {
71 authUser := "alex"
72 // check auth
73 files, _ := getUserFiles(authUser)
74 data := struct {
75 Domain string
76 PageTitle string
77 AuthUser string
78 Files []*File
79 }{c.RootDomain, c.SiteTitle, authUser, files}
80 _ = t.ExecuteTemplate(w, "my_site.html", data)
81}
82
83func loginHandler(w http.ResponseWriter, r *http.Request) {
84 if r.Method == "GET" {
85 // show page
86 data := struct {
87 Error string
88 PageTitle string
89 }{"", "Login"}
90 err := t.ExecuteTemplate(w, "login.html", data)
91 if err != nil {
92 log.Println(err)
93 renderError(w, InternalServerErrorMsg, 500)
94 return
95 }
96 } else if r.Method == "POST" {
97 r.ParseForm()
98 name := r.Form.Get("username")
99 password := r.Form.Get("password")
100 err := checkAuth(name, password)
101 if err == nil {
102 log.Println("logged in")
103 // redirect home
104 } else {
105 data := struct {
106 Error string
107 PageTitle string
108 }{"Invalid login or password", c.SiteTitle}
109 err := t.ExecuteTemplate(w, "login.html", data)
110 if err != nil {
111 log.Println(err)
112 renderError(w, InternalServerErrorMsg, 500)
113 return
114 }
115 }
116 // create session
117 // redirect home
118 // verify login
119 // check for errors
120 }
121}
122
123func registerHandler(w http.ResponseWriter, r *http.Request) {
124 if r.Method == "GET" {
125 data := struct {
126 Domain string
127 Errors []string
128 PageTitle string
129 }{c.RootDomain, nil, "Register"}
130 err := t.ExecuteTemplate(w, "register.html", data)
131 if err != nil {
132 log.Println(err)
133 renderError(w, InternalServerErrorMsg, 500)
134 return
135 }
136 } else if r.Method == "POST" {
137 }
138}
139
140// Server a user's file
141func userFile(w http.ResponseWriter, r *http.Request) {
142 userName := strings.Split(r.Host, ".")[0]
143 fileName := path.Join(c.FilesDirectory, userName, r.URL.Path)
144 extension := path.Ext(fileName)
145 log.Println(extension)
146 if extension == ".gmi" || extension == ".gemini" {
147 if strings.Contains(fileName, "..") {
148 // prevent directory traversal TODO verify
149 http.Error(w, "invalid URL path", http.StatusBadRequest)
150 } else {
151 // covert to html
152 stat, _ := os.Stat(fileName)
153 file, _ := os.Open(fileName)
154 htmlString := gmi.Parse(file).HTML()
155 log.Println(htmlString)
156 reader := strings.NewReader(htmlString)
157 w.Header().Set("Content-Type", "text/html")
158 http.ServeContent(w, r, fileName, stat.ModTime(), reader)
159 }
160 // TODO clean
161 } else {
162 http.ServeFile(w, r, fileName)
163 }
164}
165
166func runHTTPServer() {
167 log.Println("Running http server")
168 var err error
169 t, err = template.ParseGlob("./templates/*.html") // TODO make template dir configruable
170 if err != nil {
171 log.Fatal(err)
172 }
173 http.HandleFunc(c.RootDomain+"/", indexHandler)
174 http.HandleFunc(c.RootDomain+"/my_site", mySiteHandler)
175 http.HandleFunc(c.RootDomain+"/edit/", editFileHandler)
176 http.HandleFunc(c.RootDomain+"/login", loginHandler)
177 http.HandleFunc(c.RootDomain+"/register", registerHandler)
178 // http.HandleFunc("/delete/", deleteFileHandler)
179 // login+register functions
180
181 // handle user files based on subdomain
182 http.HandleFunc("/", userFile)
183 log.Fatal(http.ListenAndServe(":8080", logRequest(http.DefaultServeMux)))
184}
185
186func logRequest(handler http.Handler) http.Handler {
187 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
188 log.Printf("%s %s %s\n", r.RemoteAddr, r.Method, r.URL)
189 handler.ServeHTTP(w, r)
190 })
191}