summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--analyze_urls.py17
-rw-r--r--gitweb-redirector.go247
-rw-r--r--gitweb-redirector.service12
-rw-r--r--gitweb-redirector.socket8
-rw-r--r--go.mod5
-rw-r--r--go.sum2
7 files changed, 293 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6fa6ba6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+/.idea/
+/gitweb-redirector
diff --git a/analyze_urls.py b/analyze_urls.py
new file mode 100644
index 0000000..b41fd5c
--- /dev/null
+++ b/analyze_urls.py
@@ -0,0 +1,17 @@
+#!/usr/bin/python3
+import json
+import sys
+from urllib.parse import urlparse
+
+summary = {}
+
+for line in sys.stdin:
+ url = urlparse(line.strip())
+ if url.path == "/gitweb/" and url.query:
+ parts = {key: value
+ for key, value in [item.split("=", 1) for item in url.query.split(";")]}
+ for key, value in parts.items():
+ count = summary.setdefault(key, {}).setdefault(value, 0)
+ summary[key][value] = count + 1
+with open('summary.json', 'w') as output:
+ json.dump(summary, output)
diff --git a/gitweb-redirector.go b/gitweb-redirector.go
new file mode 100644
index 0000000..0aa74b5
--- /dev/null
+++ b/gitweb-redirector.go
@@ -0,0 +1,247 @@
+package main
+
+import (
+ "fmt"
+ "github.com/coreos/go-systemd/activation"
+ "log"
+ "net/http"
+ "net/http/fcgi"
+ "net/url"
+ "strings"
+)
+
+type gitWebRequest struct {
+}
+
+func (g gitWebRequest) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
+ query := request.URL.Query()
+ var project, target, head, fileName string
+ if pValue, ok := query["p"]; ok {
+ project = pValue[0]
+ }
+ if fValue, ok := query["f"]; ok {
+ fileName = fValue[0]
+ }
+ if hValue, ok := query["h"]; ok {
+ head = hValue[0]
+ }
+ if action, ok := query["a"]; ok {
+ switch action[0] {
+ case "atom":
+ target = atomUrl(project, fileName, head)
+ case "blobdiff":
+ target = blobDiffUrl(project, fileName, query)
+ case "blobdiff_plain":
+ target = blobDiffPlainUrl(project, fileName, query)
+ case "blob":
+ target = blobUrl(project, fileName, query)
+ case "blob_plain":
+ target = blobPlainUrl(project, fileName, query)
+ case "commit":
+ target = commitUrl(project, query)
+ case "commitdiff":
+ target = commitDiff(project, query)
+ case "commitdiff_plain":
+ target = commitDiffPlain(project, query)
+ case "patch":
+ target = commitDiffPlain(project, query)
+ case "heads":
+ target = fmt.Sprintf("/%s/refs/heads", project)
+ case "history":
+ target = historyUrl(project, fileName, query)
+ case "log":
+ target = logUrl(project, query)
+ case "rss":
+ target = atomUrl(project, fileName, head)
+ case "search":
+ target = searchUrl(project, query)
+ case "shortlog":
+ target = shortLogUrl(project, query)
+ case "tag":
+ target = tagUrl(project, query)
+ case "tags":
+ target = tagsUrl(project, query)
+ case "tree":
+ target = treeUrl(project, query)
+ case "summary":
+ target = summaryUrl(project)
+ case "snapshot":
+ target = snapshotUrl(project, query)
+ default:
+ log.Printf("unhandled action %s for uri %s", action[0], request.URL)
+ }
+ }
+
+ if target == "" {
+ if project == "" {
+ target = "/"
+ } else {
+ target = fmt.Sprintf("/%s/", project)
+ }
+ }
+ writer.Header().Add("Location", target)
+ writer.WriteHeader(301)
+}
+
+func tagsUrl(project string, query url.Values) string {
+ params := make([]string, 0)
+ params = mapParameter(query, params, "h", "h")
+ return fmt.Sprintf("/%s/refs/tags?%s", project, strings.Join(params, "&"))
+}
+
+func logUrl(project string, query url.Values) string {
+ params := make([]string, 0)
+ params = append(params, "showmsg=1")
+ params = mapParameter(query, params, "h", "id")
+ return fmt.Sprintf("/%s/log/?%s", project, strings.Join(params, "&"))
+}
+
+func getParameter(query url.Values, parameterName string) string {
+ returnValue := ""
+ if parameterValue, ok := query[parameterName]; ok {
+ returnValue = parameterValue[0]
+ }
+ return returnValue
+}
+
+func mapFormat(format string) string {
+ var mappedFormat string
+ switch format {
+ case "zip":
+ mappedFormat = "zip"
+ default:
+ mappedFormat = "tar.gz"
+ }
+ return mappedFormat
+}
+
+func mapParameter(query url.Values, params []string, sourceParameter string, targetParameter string) []string {
+ if parameterValue, ok := query[sourceParameter]; ok {
+ params = append(params, fmt.Sprintf("%s=%s", targetParameter, url.QueryEscape(parameterValue[0])))
+ }
+ return params
+}
+
+func atomUrl(project string, fileName string, head string) string {
+ target := ""
+ if project != "" {
+ target = fmt.Sprintf("/%s/atom", project)
+ if fileName != "" {
+ target = fmt.Sprintf("%s/%s", target, fileName)
+ }
+ if head != "" {
+ target = fmt.Sprintf("%s?h=%s", target, url.QueryEscape(head))
+ }
+ }
+ return target
+}
+
+func blobDiffPlainUrl(project string, fileName string, query url.Values) string {
+ params := make([]string, 0)
+ params = mapParameter(query, params, "hpb", "id")
+ return fmt.Sprintf("/%s/patch/%s?%s", project, fileName, strings.Join(params, "&"))
+}
+
+func blobDiffUrl(project string, fileName string, query url.Values) string {
+ params := make([]string, 0)
+ params = mapParameter(query, params, "hb", "id")
+ params = mapParameter(query, params, "hpb", "id2")
+ return fmt.Sprintf("/%s/diff/%s?%s", project, fileName, strings.Join(params, "&"))
+}
+
+func blobPlainUrl(project string, fileName string, query url.Values) string {
+ params := make([]string, 0)
+ params = mapParameter(query, params, "h", "id")
+ return fmt.Sprintf("/%s/plain/%s?%s", project, fileName, strings.Join(params, "&"))
+}
+
+func blobUrl(project string, fileName string, query url.Values) string {
+ target := fmt.Sprintf("/%s/tree/%s", project, fileName)
+ if hbValue, ok := query["hb"]; ok {
+ target = fmt.Sprintf("%s?id=%s", target, url.QueryEscape(hbValue[0]))
+ }
+ return target
+}
+
+func commitDiff(project string, query url.Values) string {
+ params := make([]string, 0)
+ params = mapParameter(query, params, "h", "id")
+ params = mapParameter(query, params, "hp", "id2")
+ return fmt.Sprintf("/%s/diff/?%s", project, strings.Join(params, "&"))
+}
+
+func commitDiffPlain(project string, query url.Values) string {
+ params := make([]string, 0)
+ params = mapParameter(query, params, "h", "id")
+ params = mapParameter(query, params, "hp", "id2")
+ return fmt.Sprintf("/%s/patch/?%s", project, strings.Join(params, "&"))
+}
+
+func commitUrl(project string, query url.Values) string {
+ target := fmt.Sprintf("/%s/commit/", project)
+ if hValue, ok := query["h"]; ok {
+ target = fmt.Sprintf("%s?id=%s", target, url.QueryEscape(hValue[0]))
+ }
+ return target
+}
+
+func historyUrl(project string, fileName string, query url.Values) string {
+ target := fmt.Sprintf("/%s/log/%s", project, fileName)
+ if hbValue, ok := query["hb"]; ok {
+ target = fmt.Sprintf("%s?h=%s", target, url.QueryEscape(hbValue[0]))
+ }
+ return target
+}
+
+func shortLogUrl(project string, query url.Values) string {
+ params := make([]string, 0)
+ params = mapParameter(query, params, "h", "id")
+ return fmt.Sprintf("/%s/log/?%s", project, strings.Join(params, "&"))
+}
+
+func snapshotUrl(project string, query url.Values) string {
+ projectPrefix := strings.TrimSuffix(project, ".git")
+ format := getParameter(query, "sf")
+ head := getParameter(query, "h")
+ return fmt.Sprintf("/%s/snapshot/%s-%s.%s", project, projectPrefix, url.PathEscape(head), url.PathEscape(mapFormat(format)))
+}
+
+func summaryUrl(project string) string {
+ return fmt.Sprintf("/%s/", project)
+}
+
+func tagUrl(project string, query url.Values) string {
+ ref := getParameter(query, "h")
+ ref = strings.TrimPrefix(ref, "refs/tags/")
+ return fmt.Sprintf("/%s/tag/?h=%s", project, url.QueryEscape(ref))
+}
+
+func treeUrl(project string, query url.Values) string {
+ params := make([]string, 0)
+ params = mapParameter(query, params, "hb", "id")
+ return fmt.Sprintf("/%s/tree/?%s", project, strings.Join(params, "&"))
+}
+
+func searchUrl(project string, query url.Values) string {
+ params := make([]string, 0)
+ params = mapParameter(query, params, "h", "h")
+ params = mapParameter(query, params, "s", "q")
+ params = mapParameter(query, params, "st", "qt")
+ return fmt.Sprintf("/%s/log/%s", project, strings.Join(params, "&"))
+}
+
+func main() {
+ listeners, err := activation.Listeners()
+ if err != nil {
+ log.Fatalf("cannot retrieve listeners: %s", err)
+ }
+ if len(listeners) != 1 {
+ log.Fatalf("unexpected number of socket activation (%d != 1)", len(listeners))
+ }
+
+ for {
+ if err := fcgi.Serve(listeners[0], gitWebRequest{}); err != nil {
+ log.Print("error serving requests:", err)
+ }
+ }
+}
diff --git a/gitweb-redirector.service b/gitweb-redirector.service
new file mode 100644
index 0000000..4ace7f6
--- /dev/null
+++ b/gitweb-redirector.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=FastCGI service for redirecting gitweb URLs to cgit
+After=nss-user-lookup.target
+Requires=gitweb-redirector.socket
+
+[Service]
+ExecStart=/usr/local/sbin/gitweb-redirector
+User=www-data
+Group=www-data
+
+[Install]
+Also=gitweb-redirector.socket
diff --git a/gitweb-redirector.socket b/gitweb-redirector.socket
new file mode 100644
index 0000000..898eb38
--- /dev/null
+++ b/gitweb-redirector.socket
@@ -0,0 +1,8 @@
+[Unit]
+Description=gitweb-redirector Socket
+
+[Socket]
+ListenStream=/run/gitweb-redirector.socket
+
+[Install]
+WantedBy=sockets.target
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..fd85eb0
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,5 @@
+module git.cacert.org/gitweb-redirector
+
+go 1.14
+
+require github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..7c6c1bb
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,2 @@
+github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
+github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=