code.gitea.io/gitea@v1.19.3/modules/sitemap/sitemap.go (about)

     1  // Copyright 2022 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package sitemap
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/xml"
     9  	"fmt"
    10  	"io"
    11  	"time"
    12  )
    13  
    14  const (
    15  	sitemapFileLimit = 50 * 1024 * 1024 // the maximum size of a sitemap file
    16  	urlsLimit        = 50000
    17  
    18  	schemaURL        = "http://www.sitemaps.org/schemas/sitemap/0.9"
    19  	urlsetName       = "urlset"
    20  	sitemapindexName = "sitemapindex"
    21  )
    22  
    23  // URL represents a single sitemap entry
    24  type URL struct {
    25  	URL     string     `xml:"loc"`
    26  	LastMod *time.Time `xml:"lastmod,omitempty"`
    27  }
    28  
    29  // Sitemap represents a sitemap
    30  type Sitemap struct {
    31  	XMLName   xml.Name
    32  	Namespace string `xml:"xmlns,attr"`
    33  
    34  	URLs     []URL `xml:"url"`
    35  	Sitemaps []URL `xml:"sitemap"`
    36  }
    37  
    38  // NewSitemap creates a sitemap
    39  func NewSitemap() *Sitemap {
    40  	return &Sitemap{
    41  		XMLName:   xml.Name{Local: urlsetName},
    42  		Namespace: schemaURL,
    43  	}
    44  }
    45  
    46  // NewSitemapIndex creates a sitemap index.
    47  func NewSitemapIndex() *Sitemap {
    48  	return &Sitemap{
    49  		XMLName:   xml.Name{Local: sitemapindexName},
    50  		Namespace: schemaURL,
    51  	}
    52  }
    53  
    54  // Add adds a URL to the sitemap
    55  func (s *Sitemap) Add(u URL) {
    56  	if s.XMLName.Local == sitemapindexName {
    57  		s.Sitemaps = append(s.Sitemaps, u)
    58  	} else {
    59  		s.URLs = append(s.URLs, u)
    60  	}
    61  }
    62  
    63  // WriteTo writes the sitemap to a response
    64  func (s *Sitemap) WriteTo(w io.Writer) (int64, error) {
    65  	if l := len(s.URLs); l > urlsLimit {
    66  		return 0, fmt.Errorf("The sitemap contains %d URLs, but only %d are allowed", l, urlsLimit)
    67  	}
    68  	if l := len(s.Sitemaps); l > urlsLimit {
    69  		return 0, fmt.Errorf("The sitemap contains %d sub-sitemaps, but only %d are allowed", l, urlsLimit)
    70  	}
    71  	buf := bytes.NewBufferString(xml.Header)
    72  	if err := xml.NewEncoder(buf).Encode(s); err != nil {
    73  		return 0, err
    74  	}
    75  	if err := buf.WriteByte('\n'); err != nil {
    76  		return 0, err
    77  	}
    78  	if buf.Len() > sitemapFileLimit {
    79  		return 0, fmt.Errorf("The sitemap has %d bytes, but only %d are allowed", buf.Len(), sitemapFileLimit)
    80  	}
    81  	return buf.WriteTo(w)
    82  }