Monorepo for Tangled tangled.org
5

Configure Feed

Select the types of activity you want to include in your feed.

at icy/kxpzqo 3.5 kB View raw
1package state 2 3import ( 4 "context" 5 "fmt" 6 "io" 7 "net/http" 8 9 "github.com/bluesky-social/indigo/atproto/identity" 10 "github.com/go-chi/chi/v5" 11 "tangled.org/core/appview/models" 12) 13 14// allowedResponseHeaders is the set of headers we will forward from the knot 15// back to the client. everything else is stripped. 16var allowedResponseHeaders = map[string]bool{ 17 "Content-Encoding": true, 18 "Transfer-Encoding": true, 19 "Cache-Control": true, 20 "Expires": true, 21 "Pragma": true, 22} 23 24func copyAllowedHeaders(dst, src http.Header) { 25 for k, vv := range src { 26 if allowedResponseHeaders[http.CanonicalHeaderKey(k)] { 27 for _, v := range vv { 28 dst.Add(k, v) 29 } 30 } 31 } 32} 33 34func setGitHeaders(w http.ResponseWriter, contentType string) { 35 w.Header().Set("Content-Type", contentType) 36 w.Header().Set("Content-Disposition", "attachment") 37 w.Header().Set("X-Content-Type-Options", "nosniff") 38} 39 40func (s *State) InfoRefs(w http.ResponseWriter, r *http.Request) { 41 repo := r.Context().Value("repo").(*models.Repo) 42 43 scheme := "https" 44 if s.config.Core.Dev { 45 scheme = "http" 46 } 47 48 service := r.URL.Query().Get("service") 49 if service != "git-receive-pack" { 50 go s.notifier.Clone(context.Background(), repo) 51 } 52 53 targetURL := fmt.Sprintf("%s://%s/%s/info/refs?%s", scheme, repo.Knot, repo.RepoIdentifier(), r.URL.RawQuery) 54 http.Redirect(w, r, targetURL, http.StatusTemporaryRedirect) 55} 56 57func (s *State) UploadArchive(w http.ResponseWriter, r *http.Request) { 58 repo := r.Context().Value("repo").(*models.Repo) 59 60 scheme := "https" 61 if s.config.Core.Dev { 62 scheme = "http" 63 } 64 65 targetURL := fmt.Sprintf("%s://%s/%s/git-upload-archive?%s", scheme, repo.Knot, repo.RepoIdentifier(), r.URL.RawQuery) 66 http.Redirect(w, r, targetURL, http.StatusTemporaryRedirect) 67} 68 69func (s *State) UploadPack(w http.ResponseWriter, r *http.Request) { 70 repo := r.Context().Value("repo").(*models.Repo) 71 72 scheme := "https" 73 if s.config.Core.Dev { 74 scheme = "http" 75 } 76 77 targetURL := fmt.Sprintf("%s://%s/%s/git-upload-pack?%s", scheme, repo.Knot, repo.RepoIdentifier(), r.URL.RawQuery) 78 http.Redirect(w, r, targetURL, http.StatusTemporaryRedirect) 79} 80 81func (s *State) ReceivePack(w http.ResponseWriter, r *http.Request) { 82 repo := r.Context().Value("repo").(*models.Repo) 83 84 scheme := "https" 85 if s.config.Core.Dev { 86 scheme = "http" 87 } 88 89 targetURL := fmt.Sprintf("%s://%s/%s/git-receive-pack?%s", scheme, repo.Knot, repo.RepoIdentifier(), r.URL.RawQuery) 90 s.proxyRequest(w, r, targetURL, "application/x-git-receive-pack-result") 91} 92 93func (s *State) proxyRequest(w http.ResponseWriter, r *http.Request, targetURL string, contentType string) { 94 client := &http.Client{} 95 96 proxyReq, err := http.NewRequest(r.Method, targetURL, r.Body) 97 if err != nil { 98 http.Error(w, err.Error(), http.StatusInternalServerError) 99 return 100 } 101 102 proxyReq.Header = r.Header.Clone() 103 104 repoOwnerHandle := chi.URLParam(r, "user") 105 if id, ok := r.Context().Value("resolvedId").(identity.Identity); ok && !id.Handle.IsInvalidHandle() { 106 repoOwnerHandle = id.Handle.String() 107 } 108 proxyReq.Header.Set("x-tangled-repo-owner-handle", repoOwnerHandle) 109 110 resp, err := client.Do(proxyReq) 111 if err != nil { 112 http.Error(w, err.Error(), http.StatusInternalServerError) 113 return 114 } 115 defer resp.Body.Close() 116 117 // selectively copy only allowed headers 118 copyAllowedHeaders(w.Header(), resp.Header) 119 120 setGitHeaders(w, contentType) 121 122 w.WriteHeader(resp.StatusCode) 123 124 if _, err := io.Copy(w, resp.Body); err != nil { 125 http.Error(w, err.Error(), http.StatusInternalServerError) 126 return 127 } 128}