Sonar: the off-site redirect and three autofocus attributes !441

merged merged by cmc on 2026-09-20 05:26 UTC · krz/gitbay:sonar-238 into main

5 files changed, +26 −3

Layout: unified · split

internal/httpd/routes.go +5
@@ -263,6 +263,11 @@ func (s *Server) unmatched(mux *http.ServeMux) http.HandlerFunc {
263263 // The fallback itself is registered at "/", so a miss
264264 // reports that pattern; a real route reports its own.
265265 if _, pattern := mux.Handler(trimmed); pattern != "" && pattern != "/" {
266 // net/http fills Scheme and Host from an
267 // absolute-form request line, which RFC 7230
268 // requires a server to accept; carrying them
269 // into Location sends the reader off-site.
270 u.Scheme, u.Host, u.User = "", "", nil
266271 http.Redirect(w, r, u.String(), http.StatusMovedPermanently)
267272 return
268273 }
internal/httpd/trailingslash_test.go +18
@@ -1,6 +1,7 @@
11package httpd
22
33import (
4 "bufio"
45 "net/http"
56 "net/http/httptest"
67 "strings"
@@ -37,6 +38,23 @@ func TestTrailingSlashRedirects(t *testing.T) {
3738 t.Errorf("%s: Location %q leaves the site", p, loc)
3839 }
3940 }
41 // An absolute-form request line, which RFC 7230 requires a server to
42 // accept, fills URL.Scheme and URL.Host. Neither may reach Location.
43 // ReadRequest also takes Host from the URL; it is pinned back to the
44 // site so this stays a test of the forge handler rather than of the
45 // pages router.
46 raw := "GET http://evil.example/cmc/ HTTP/1.1\r\nHost: forge.test\r\n\r\n"
47 abs, err := http.ReadRequest(bufio.NewReader(strings.NewReader(raw)))
48 if err != nil {
49 t.Fatal(err)
50 }
51 abs.Host = "forge.test"
52 aw := httptest.NewRecorder()
53 h.ServeHTTP(aw, abs)
54 if loc := aw.Header().Get("Location"); loc != "/cmc" {
55 t.Errorf("absolute-form request: Location %q, want %q", loc, "/cmc")
56 }
57
4058 r := httptest.NewRequest("POST", "/cmc/", nil)
4159 r.Host = "forge.test"
4260 w := httptest.NewRecorder()
internal/web/templates/globalsearch.html +1 −1
@@ -20,7 +20,7 @@
2020 {{if and .Query (not .QueryErr)}}<p class="meta">{{len .Results}} {{if eq (len .Results) 1}}result{{else}}results{{end}} for <q>{{.Query}}</q>{{if .Kind}} in {{.Kind}}{{end}}</p>{{end}}
2121</div>
2222<form method="get" action="/search" class="searchform">
23 <input type="search" name="q" aria-label="Search" value="{{.Query}}" placeholder="repository names and topics, issue and merge request text" autofocus>
23 <input type="search" name="q" aria-label="Search" value="{{.Query}}" placeholder="repository names and topics, issue and merge request text">
2424 {{if .Kind}}<input type="hidden" name="kind" value="{{.Kind}}">{{end}}
2525 <button type="submit" class="btn">Search</button>
2626</form>
internal/web/templates/register.html +1 −1
@@ -6,7 +6,7 @@
66{{else}}<p class="lede">Open registration. Your account activates once you verify your email.</p>{{end}}
77{{if .Error}}<p class="error" role="alert">{{.Error}}</p>{{end}}
88<form method="post" action="/register" class="signupform">
9<div class="field"><label for="username">Username</label><input type="text" id="username" name="username" value="{{.Username}}" required autofocus></div>
9<div class="field"><label for="username">Username</label><input type="text" id="username" name="username" value="{{.Username}}" required></div>
1010{{if eq .Mode "invite"}}<div class="field"><label for="invite">Invite code</label><input type="text" id="invite" name="invite" required></div>
1111{{else}}<div class="field"><label for="email">Email</label><input type="text" id="email" name="email" required></div>{{end}}
1212<div class="field"><label for="key">SSH public key</label>
internal/web/templates/search.html +1 −1
@@ -3,7 +3,7 @@
33{{define "content"}}
44<h1>Search</h1>
55<form method="get" action="/{{.Repo.OwnerName}}/{{.Repo.Name}}/search" class="searchform">
6 <input type="search" name="q" aria-label="Search file contents" value="{{.Query}}" placeholder="search file contents on {{.Ref}}" autofocus>
6 <input type="search" name="q" aria-label="Search file contents" value="{{.Query}}" placeholder="search file contents on {{.Ref}}">
77 <button type="submit" class="btn">Search</button>
88</form>
99{{if .QueryErr}}<p class="error" role="alert">{{.QueryErr}}</p>