Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Trzcinski <ayufan@ayufan.eu>2016-02-23 14:40:41 +0300
committerKamil Trzcinski <ayufan@ayufan.eu>2016-02-23 14:40:41 +0300
commitd7233de6883fbb83cf445b19cdc95a119caa52b8 (patch)
tree02228c55ebcb4da0171d587f22114793e888b683 /domain.go
parent4a2c6807551bb9e544daed007df550e2a4333b96 (diff)
Added support for serving the 404 page
Diffstat (limited to 'domain.go')
-rw-r--r--domain.go104
1 files changed, 85 insertions, 19 deletions
diff --git a/domain.go b/domain.go
index 32a8b09c..49df3762 100644
--- a/domain.go
+++ b/domain.go
@@ -4,9 +4,12 @@ import (
"crypto/tls"
"errors"
"fmt"
+ "io"
+ "mime"
"net/http"
"os"
"path/filepath"
+ "strconv"
"strings"
)
@@ -18,29 +21,54 @@ type domain struct {
certificateError error
}
-func (d *domain) notFound(w http.ResponseWriter, r *http.Request) {
- http.NotFound(w, r)
-}
-
-func (d *domain) serveFile(w http.ResponseWriter, r *http.Request, fullPath string) bool {
+func (d *domain) serveFile(w http.ResponseWriter, r *http.Request, fullPath string) error {
// Open and serve content of file
file, err := os.Open(fullPath)
if err != nil {
- return false
+ return err
}
defer file.Close()
fi, err := file.Stat()
if err != nil {
- return false
+ return err
}
println("Serving", fullPath, "for", r.URL.Path)
http.ServeContent(w, r, filepath.Base(file.Name()), fi.ModTime(), file)
- return true
+ return nil
}
-func (d *domain) resolvePath(w http.ResponseWriter, r *http.Request, projectName, subPath string) (fullPath string, err error) {
+func (d *domain) serveCustomFile(w http.ResponseWriter, r *http.Request, code int, fullPath string) error {
+ // Open and serve content of file
+ file, err := os.Open(fullPath)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ fi, err := file.Stat()
+ if err != nil {
+ return err
+ }
+
+ println("Serving", fullPath, "for", r.URL.Path, "with", code)
+
+ // Serve the file
+ _, haveType := w.Header()["Content-Type"]
+ if !haveType {
+ ctype := mime.TypeByExtension(filepath.Ext(fullPath))
+ w.Header().Set("Content-Type", ctype)
+ }
+ w.Header().Set("Content-Length", strconv.FormatInt(fi.Size(), 10))
+ w.WriteHeader(code)
+ if r.Method != "HEAD" {
+ io.CopyN(w, file, fi.Size())
+ }
+ return nil
+}
+
+func (d *domain) resolvePath(projectName, subPath string) (fullPath string, err error) {
publicPath := filepath.Join(d.Group, projectName, "public")
fullPath = filepath.Join(publicPath, subPath)
@@ -56,6 +84,25 @@ func (d *domain) resolvePath(w http.ResponseWriter, r *http.Request, projectName
return
}
+func (d *domain) tryNotFound(w http.ResponseWriter, r *http.Request, projectName string) error {
+ page404, err := d.resolvePath(projectName, "404.html")
+ if err != nil {
+ return err
+ }
+
+ // Make sure that file is not symlink
+ fi, err := os.Lstat(page404)
+ if err != nil && !fi.Mode().IsRegular() {
+ return err
+ }
+
+ err = d.serveCustomFile(w, r, http.StatusNotFound, page404)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
func (d *domain) checkPath(w http.ResponseWriter, r *http.Request, path string) (fullPath string, err error) {
fullPath = path
fi, err := os.Lstat(fullPath)
@@ -85,45 +132,64 @@ func (d *domain) checkPath(w http.ResponseWriter, r *http.Request, path string)
return
}
-func (d *domain) tryFile(w http.ResponseWriter, r *http.Request, projectName, subPath string) bool {
- path, err := d.resolvePath(w, r, projectName, subPath)
+func (d *domain) tryFile(w http.ResponseWriter, r *http.Request, projectName, subPath string) error {
+ path, err := d.resolvePath(projectName, subPath)
if err != nil {
- return false
+ return err
}
path, err = d.checkPath(w, r, path)
if err != nil {
- return false
+ return err
}
return d.serveFile(w, r, path)
}
func (d *domain) serveFromGroup(w http.ResponseWriter, r *http.Request) {
- // The Path always contains "/" at the beggining
+ // The Path always contains "/" at the beginning
split := strings.SplitN(r.URL.Path, "/", 3)
+ // Try to serve file for http://group.example.com/subpath/... => /group/subpath/...
if len(split) >= 2 {
subPath := ""
if len(split) >= 3 {
subPath = split[2]
}
- if d.tryFile(w, r, split[1], subPath) {
+ if d.tryFile(w, r, split[1], subPath) == nil {
return
}
}
- if r.Host != "" && d.tryFile(w, r, strings.ToLower(r.Host), r.URL.Path) {
+ // Try to serve file for http://group.example.com/... => /group/group.example.com/...
+ if r.Host != "" && d.tryFile(w, r, strings.ToLower(r.Host), r.URL.Path) == nil {
return
}
- d.notFound(w, r)
+ // Try serving not found page for http://group.example.com/subpath/ => /group/subpath/404.html
+ if len(split) >= 2 && d.tryNotFound(w, r, split[1]) == nil {
+ return
+ }
+
+ // Try serving not found page for http://group.example.com/ => /group/group.example.com/404.html
+ if r.Host != "" && d.tryFile(w, r, strings.ToLower(r.Host), r.URL.Path) == nil {
+ return
+ }
+
+ // Serve generic not found
+ http.NotFound(w, r)
}
func (d *domain) serveFromConfig(w http.ResponseWriter, r *http.Request) {
- if d.tryFile(w, r, d.Project, r.URL.Path) {
+ // Try to serve file for http://host/... => /group/project/...
+ if d.tryFile(w, r, d.Project, r.URL.Path) == nil {
return
}
- d.notFound(w, r)
+ // Try serving not found page for http://host/ => /group/project/404.html
+ if d.tryNotFound(w, r, d.Project) == nil {
+ return
+ }
+
+ http.NotFound(w, r)
}
func (d *domain) ensureCertificate() (*tls.Certificate, error) {