Compare commits

..

No commits in common. "55c6433faca75cf69adc2bfb2450fe0b485354e4" and "58e642c1d67d36ce255abf13d08b3bcac0dccfb7" have entirely different histories.

5 changed files with 75 additions and 189 deletions

View File

@ -735,9 +735,9 @@ and
- `GRAVATAR_SOURCE`: **gravatar**: Can be `gravatar`, `duoshuo` or anything like - `GRAVATAR_SOURCE`: **gravatar**: Can be `gravatar`, `duoshuo` or anything like
`http://cn.gravatar.com/avatar/`. `http://cn.gravatar.com/avatar/`.
- `DISABLE_GRAVATAR`: **false**: Enable this to use local avatars only. **DEPRECATED [v1.18+]** moved to database. Use admin panel to configure. - `DISABLE_GRAVATAR`: **false**: Enable this to use local avatars only.
- `ENABLE_FEDERATED_AVATAR`: **false**: Enable support for federated avatars (see - `ENABLE_FEDERATED_AVATAR`: **false**: Enable support for federated avatars (see
[http://www.libravatar.org](http://www.libravatar.org)). **DEPRECATED [v1.18+]** moved to database. Use admin panel to configure. [http://www.libravatar.org](http://www.libravatar.org)).
- `AVATAR_STORAGE_TYPE`: **default**: Storage type defined in `[storage.xxx]`. Default is `default` which will read `[storage]` if no section `[storage]` will be a type `local`. - `AVATAR_STORAGE_TYPE`: **default**: Storage type defined in `[storage.xxx]`. Default is `default` which will read `[storage]` if no section `[storage]` will be a type `local`.
- `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store user avatar image files. - `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store user avatar image files.

View File

@ -12,62 +12,48 @@ import (
"time" "time"
) )
const ( // sitemapFileLimit contains the maximum size of a sitemap file
sitemapFileLimit = 50 * 1024 * 1024 // the maximum size of a sitemap file const sitemapFileLimit = 50 * 1024 * 1024
urlsLimit = 50000
schemaURL = "http://www.sitemaps.org/schemas/sitemap/0.9" // Url represents a single sitemap entry
urlsetName = "urlset"
sitemapindexName = "sitemapindex"
)
// URL represents a single sitemap entry
type URL struct { type URL struct {
URL string `xml:"loc"` URL string `xml:"loc"`
LastMod *time.Time `xml:"lastmod,omitempty"` LastMod *time.Time `xml:"lastmod,omitempty"`
} }
// Sitemap represents a sitemap // SitemapUrl represents a sitemap
type Sitemap struct { type Sitemap struct {
XMLName xml.Name XMLName xml.Name
Namespace string `xml:"xmlns,attr"` Namespace string `xml:"xmlns,attr"`
URLs []URL `xml:"url"` URLs []URL `xml:"url"`
Sitemaps []URL `xml:"sitemap"`
} }
// NewSitemap creates a sitemap // NewSitemap creates a sitemap
func NewSitemap() *Sitemap { func NewSitemap() *Sitemap {
return &Sitemap{ return &Sitemap{
XMLName: xml.Name{Local: urlsetName}, XMLName: xml.Name{Local: "urlset"},
Namespace: schemaURL, Namespace: "http://www.sitemaps.org/schemas/sitemap/0.9",
} }
} }
// NewSitemapIndex creates a sitemap index. // NewSitemap creates a sitemap index.
func NewSitemapIndex() *Sitemap { func NewSitemapIndex() *Sitemap {
return &Sitemap{ return &Sitemap{
XMLName: xml.Name{Local: sitemapindexName}, XMLName: xml.Name{Local: "sitemapindex"},
Namespace: schemaURL, Namespace: "http://www.sitemaps.org/schemas/sitemap/0.9",
} }
} }
// Add adds a URL to the sitemap // Add adds a URL to the sitemap
func (s *Sitemap) Add(u URL) { func (s *Sitemap) Add(u URL) {
if s.XMLName.Local == sitemapindexName {
s.Sitemaps = append(s.Sitemaps, u)
} else {
s.URLs = append(s.URLs, u) s.URLs = append(s.URLs, u)
} }
}
// WriteTo writes the sitemap to a response // Write writes the sitemap to a response
func (s *Sitemap) WriteTo(w io.Writer) (int64, error) { func (s *Sitemap) WriteTo(w io.Writer) (int64, error) {
if l := len(s.URLs); l > urlsLimit { if len(s.URLs) > 50000 {
return 0, fmt.Errorf("The sitemap contains %d URLs, but only %d are allowed", l, urlsLimit) return 0, fmt.Errorf("The sitemap contains too many URLs: %d", len(s.URLs))
}
if l := len(s.Sitemaps); l > urlsLimit {
return 0, fmt.Errorf("The sitemap contains %d sub-sitemaps, but only %d are allowed", l, urlsLimit)
} }
buf := bytes.NewBufferString(xml.Header) buf := bytes.NewBufferString(xml.Header)
if err := xml.NewEncoder(buf).Encode(s); err != nil { if err := xml.NewEncoder(buf).Encode(s); err != nil {
@ -77,7 +63,7 @@ func (s *Sitemap) WriteTo(w io.Writer) (int64, error) {
return 0, err return 0, err
} }
if buf.Len() > sitemapFileLimit { if buf.Len() > sitemapFileLimit {
return 0, fmt.Errorf("The sitemap has %d bytes, but only %d are allowed", buf.Len(), sitemapFileLimit) return 0, fmt.Errorf("The sitemap is too big: %d", buf.Len())
} }
return buf.WriteTo(w) return buf.WriteTo(w)
} }

View File

@ -7,6 +7,7 @@ package sitemap
import ( import (
"bytes" "bytes"
"encoding/xml" "encoding/xml"
"fmt"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -14,154 +15,63 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestNewSitemap(t *testing.T) { func TestOk(t *testing.T) {
testReal := func(s *Sitemap, name string, urls []URL, expected string) {
for _, url := range urls {
s.Add(url)
}
buf := &bytes.Buffer{}
_, err := s.WriteTo(buf)
assert.NoError(t, nil, err)
assert.Equal(t, xml.Header+"<"+name+" xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">"+expected+"</"+name+">\n", buf.String())
}
test := func(urls []URL, expected string) {
testReal(NewSitemap(), "urlset", urls, expected)
testReal(NewSitemapIndex(), "sitemapindex", urls, expected)
}
ts := time.Unix(1651322008, 0).UTC() ts := time.Unix(1651322008, 0).UTC()
tests := []struct { test(
name string []URL{},
urls []URL "",
want string )
wantErr string test(
}{ []URL{
{
name: "empty",
urls: []URL{},
want: xml.Header + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"" +
"</urlset>\n",
},
{
name: "regular",
urls: []URL{
{URL: "https://gitea.io/test1", LastMod: &ts}, {URL: "https://gitea.io/test1", LastMod: &ts},
}, },
want: xml.Header + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` + "<url><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></url>",
"<url><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></url>" + )
"</urlset>\n", test(
[]URL{
{URL: "https://gitea.io/test2", LastMod: nil},
}, },
{ "<url><loc>https://gitea.io/test2</loc></url>",
name: "without lastmod", )
urls: []URL{ test(
{URL: "https://gitea.io/test1"}, []URL{
},
want: xml.Header + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"<url><loc>https://gitea.io/test1</loc></url>" +
"</urlset>\n",
},
{
name: "multiple",
urls: []URL{
{URL: "https://gitea.io/test1", LastMod: &ts}, {URL: "https://gitea.io/test1", LastMod: &ts},
{URL: "https://gitea.io/test2", LastMod: nil}, {URL: "https://gitea.io/test2", LastMod: nil},
}, },
want: xml.Header + `<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"<url><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></url>"+ "<url><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></url>"+
"<url><loc>https://gitea.io/test2</loc></url>" + "<url><loc>https://gitea.io/test2</loc></url>",
"</urlset>\n", )
},
{
name: "too many urls",
urls: make([]URL, 50001),
wantErr: "The sitemap contains 50001 URLs, but only 50000 are allowed",
},
{
name: "too big file",
urls: []URL{
{URL: strings.Repeat("b", 50*1024*1024+1)},
},
wantErr: "The sitemap has 52428932 bytes, but only 52428800 are allowed",
},
} }
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { func TestTooManyURLs(t *testing.T) {
s := NewSitemap() s := NewSitemap()
for _, url := range tt.urls { for i := 0; i < 50001; i++ {
s.Add(url) s.Add(URL{URL: fmt.Sprintf("https://gitea.io/test%d", i)})
} }
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
_, err := s.WriteTo(buf) _, err := s.WriteTo(buf)
if tt.wantErr != "" { assert.EqualError(t, err, "The sitemap contains too many URLs: 50001")
assert.EqualError(t, err, tt.wantErr)
} else {
assert.NoError(t, err)
assert.Equalf(t, tt.want, buf.String(), "NewSitemap()")
}
})
}
} }
func TestNewSitemapIndex(t *testing.T) { func TestSitemapTooBig(t *testing.T) {
ts := time.Unix(1651322008, 0).UTC() s := NewSitemap()
s.Add(URL{URL: strings.Repeat("b", sitemapFileLimit)})
tests := []struct {
name string
urls []URL
want string
wantErr string
}{
{
name: "empty",
urls: []URL{},
want: xml.Header + `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"" +
"</sitemapindex>\n",
},
{
name: "regular",
urls: []URL{
{URL: "https://gitea.io/test1", LastMod: &ts},
},
want: xml.Header + `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"<sitemap><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></sitemap>" +
"</sitemapindex>\n",
},
{
name: "without lastmod",
urls: []URL{
{URL: "https://gitea.io/test1"},
},
want: xml.Header + `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"<sitemap><loc>https://gitea.io/test1</loc></sitemap>" +
"</sitemapindex>\n",
},
{
name: "multiple",
urls: []URL{
{URL: "https://gitea.io/test1", LastMod: &ts},
{URL: "https://gitea.io/test2", LastMod: nil},
},
want: xml.Header + `<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">` +
"<sitemap><loc>https://gitea.io/test1</loc><lastmod>2022-04-30T12:33:28Z</lastmod></sitemap>" +
"<sitemap><loc>https://gitea.io/test2</loc></sitemap>" +
"</sitemapindex>\n",
},
{
name: "too many sitemaps",
urls: make([]URL, 50001),
wantErr: "The sitemap contains 50001 sub-sitemaps, but only 50000 are allowed",
},
{
name: "too big file",
urls: []URL{
{URL: strings.Repeat("b", 50*1024*1024+1)},
},
wantErr: "The sitemap has 52428952 bytes, but only 52428800 are allowed",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := NewSitemapIndex()
for _, url := range tt.urls {
s.Add(url)
}
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
_, err := s.WriteTo(buf) _, err := s.WriteTo(buf)
if tt.wantErr != "" { assert.EqualError(t, err, "The sitemap is too big: 52428931")
assert.EqualError(t, err, tt.wantErr)
} else {
assert.NoError(t, err)
assert.Equalf(t, tt.want, buf.String(), "NewSitemapIndex()")
}
})
}
} }

View File

@ -77,14 +77,7 @@ func HTMLRenderer(ctx context.Context) (context.Context, *render.Render) {
if !setting.IsProd { if !setting.IsProd {
watcher.CreateWatcher(ctx, "HTML Templates", &watcher.CreateWatcherOpts{ watcher.CreateWatcher(ctx, "HTML Templates", &watcher.CreateWatcherOpts{
PathsCallback: walkTemplateFiles, PathsCallback: walkTemplateFiles,
BetweenCallback: func() { BetweenCallback: renderer.CompileTemplates,
defer func() {
if err := recover(); err != nil {
log.Error("PANIC: %v\n%s", err, log.Stack(2))
}
}()
renderer.CompileTemplates()
},
}) })
} }
return context.WithValue(ctx, rendererKey, renderer), renderer return context.WithValue(ctx, rendererKey, renderer), renderer

View File

@ -149,8 +149,8 @@ func Install(ctx *context.Context) {
// Server and other services settings // Server and other services settings
form.OfflineMode = setting.OfflineMode form.OfflineMode = setting.OfflineMode
form.DisableGravatar = setting.DisableGravatar // when installing, there is no database connection so that given a default value form.DisableGravatar = false // when installing, there is no database connection so that given a default value
form.EnableFederatedAvatar = setting.EnableFederatedAvatar // when installing, there is no database connection so that given a default value form.EnableFederatedAvatar = false // when installing, there is no database connection so that given a default value
form.EnableOpenIDSignIn = setting.Service.EnableOpenIDSignIn form.EnableOpenIDSignIn = setting.Service.EnableOpenIDSignIn
form.EnableOpenIDSignUp = setting.Service.EnableOpenIDSignUp form.EnableOpenIDSignUp = setting.Service.EnableOpenIDSignUp
@ -443,13 +443,10 @@ func SubmitInstall(ctx *context.Context) {
cfg.Section("server").Key("OFFLINE_MODE").SetValue(fmt.Sprint(form.OfflineMode)) cfg.Section("server").Key("OFFLINE_MODE").SetValue(fmt.Sprint(form.OfflineMode))
// if you are reinstalling, this maybe not right because of missing version // if you are reinstalling, this maybe not right because of missing version
if err := system_model.SetSettingNoVersion(system_model.KeyPictureDisableGravatar, strconv.FormatBool(form.DisableGravatar)); err != nil { if err := system_model.SetSettingNoVersion(system_model.KeyPictureDisableGravatar, strconv.FormatBool(form.DisableGravatar)); err != nil {
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form) ctx.RenderWithErr(ctx.Tr("install.secret_key_failed", err), tplInstall, &form)
return
}
if err := system_model.SetSettingNoVersion(system_model.KeyPictureEnableFederatedAvatar, strconv.FormatBool(form.EnableFederatedAvatar)); err != nil {
ctx.RenderWithErr(ctx.Tr("install.save_config_failed", err), tplInstall, &form)
return return
} }
cfg.Section("picture").Key("ENABLE_FEDERATED_AVATAR").SetValue(fmt.Sprint(form.EnableFederatedAvatar))
cfg.Section("openid").Key("ENABLE_OPENID_SIGNIN").SetValue(fmt.Sprint(form.EnableOpenIDSignIn)) cfg.Section("openid").Key("ENABLE_OPENID_SIGNIN").SetValue(fmt.Sprint(form.EnableOpenIDSignIn))
cfg.Section("openid").Key("ENABLE_OPENID_SIGNUP").SetValue(fmt.Sprint(form.EnableOpenIDSignUp)) cfg.Section("openid").Key("ENABLE_OPENID_SIGNUP").SetValue(fmt.Sprint(form.EnableOpenIDSignUp))
cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(fmt.Sprint(form.DisableRegistration)) cfg.Section("service").Key("DISABLE_REGISTRATION").SetValue(fmt.Sprint(form.DisableRegistration))