8000 [pull] main from miniflux:main by pull[bot] · Pull Request #228 · suhaoGe/miniflux · GitHub
[go: up one dir, main page]

Skip to content
Merged 8000
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/scripts/commit-checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

# Conventional commit pattern (including Git revert messages)
CONVENTIONAL_COMMIT_PATTERN: str = (
r"^((build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\([a-z0-9-]+\))?!?: .{1,100}|Revert .+)"
r"^((build|chore|ci|docs|feat|fix|perf|refactor|revert|security|style|test)(\([a-z0-9-]+\))?!?: .{1,100}|Revert .+)"
)


Expand Down
8 changes: 4 additions & 4 deletions internal/googlereader/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@ func (h *handler) streamItemIDsHandler(w http.ResponseWriter, r *http.Request) {
}
}

func (h *handler) handleReadingListStreamHandler(w http.ResponseWriter, r *http.Request, rm RequestModifiers) {
func (h *handler) handleReadingListStreamHandler(w http.ResponseWriter, r *http.Request, rm requestModifiers) {
clientIP := request.ClientIP(r)

slog.Debug("[GoogleReader] Handle ReadingListStream",
Expand Down Expand Up @@ -1126,7 +1126,7 @@ func (h *handler) handleReadingListStreamHandler(w http.ResponseWriter, r *http.
json.OK(w, r, streamIDResponse{itemRefs, continuation})
}

func (h *handler) handleStarredStreamHandler(w http.ResponseWriter, r *http.Request, rm RequestModifiers) {
func (h *handler) handleStarredStreamHandler(w http.ResponseWriter, r *http.Request, rm requestModifiers) {
builder := h.store.NewEntryQueryBuilder(rm.UserID)
builder.WithoutStatus(model.EntryStatusRemoved)
builder.WithStarred(true)
Expand Down Expand Up @@ -1164,7 +1164,7 @@ func (h *handler) handleStarredStreamHandler(w http.ResponseWriter, r *http.Requ
json.OK(w, r, streamIDResponse{itemRefs, continuation})
}

func (h *handler) handleReadStreamHandler(w http.ResponseWriter, r *http.Request, rm RequestModifiers) {
func (h *handler) handleReadStreamHandler(w http.ResponseWriter, r *http.Request, rm requestModifiers) {
builder := h.store.NewEntryQueryBuilder(rm.UserID)
builder.WithoutStatus(model.EntryStatusRemoved)
builder.WithStatus(model.EntryStatusRead)
Expand Down Expand Up @@ -1202,7 +1202,7 @@ func (h *handler) handleReadStreamHandler(w http.ResponseWriter, r *http.Request
json.OK(w, r, streamIDResponse{itemRefs, continuation})
}

func (h *handler) handleFeedStreamHandler(w http.ResponseWriter, r *http.Request, rm RequestModifiers) {
func (h *handler) handleFeedStreamHandler(w http.ResponseWriter, r *http.Request, rm requestModifiers) {
feedID, err := strconv.ParseInt(rm.Streams[0].ID, 10, 64)
if err != nil {
json.ServerError(w, r, err)
Expand Down
14 changes: 7 additions & 7 deletions internal/googlereader/request_modifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"miniflux.app/v2/internal/http/request"
)

type RequestModifiers struct {
type requestModifiers struct {
ExcludeTargets []Stream
FilterTargets []Stream
Streams []Stream
Expand All @@ -24,7 +24,7 @@ type RequestModifiers struct {
UserID int64
}

func (r RequestModifiers) String() string {
func (r requestModifiers) String() string {
var results []string

results = append(results, fmt.Sprintf("UserID: %d", r.UserID))
Expand Down Expand Up @@ -57,9 +57,9 @@ func (r RequestModifiers) String() string {
return strings.Join(results, "; ")
}

func parseStreamFilterFromRequest(r *http.Request) (RequestModifiers, error) {
func parseStreamFilterFromRequest(r *http.Request) (requestModifiers, error) {
userID := request.UserID(r)
result := RequestModifiers{
result := requestModifiers{
SortDirection: "desc",
UserID: userID,
}
Expand All @@ -71,16 +71,16 @@ func parseStreamFilterFromRequest(r *http.Request) (RequestModifiers, error) {
var err error
result.Streams, err = getStreams(request.QueryStringParamList(r, paramStreamID), userID)
if err != nil {
return RequestModifiers{}, err
return requestModifiers{}, err
}
result.ExcludeTargets, err = getStreams(request.QueryStringParamList(r, paramStreamExcludes), userID)
if err != nil {
return RequestModifiers{}, err
return requestModifiers{}, err
}

result.FilterTargets, err = getStreams(request.QueryStringParamList(r, paramStreamFilters), userID)
if err != nil {
return RequestModifiers{}, err
return requestModifiers{}, err
}

result.Count = request.QueryIntParam(r, paramStreamMaxItems, 0)
Expand Down
24 changes: 9 additions & 15 deletions internal/http/server/httpd.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"miniflux.app/v2/internal/http/request"
"miniflux.app/v2/internal/storage"
"miniflux.app/v2/internal/ui"
"miniflux.app/v2/internal/version"
"miniflux.app/v2/internal/worker"

"github.com/gorilla/mux"
Expand Down Expand Up @@ -72,22 +71,23 @@ func StartWebServer(store *storage.Storage, pool *worker.Pool) []*http.Server {
Handler: setupHandler(store, pool),
}

if !strings.HasPrefix(listenAddr, "/") && os.Getenv("LISTEN_PID") != strconv.Itoa(os.Getpid()) {
isUNIXSocket := strings.HasPrefix(listenAddr, "/")
isListenPID := os.Getenv("LISTEN_PID") == strconv.Itoa(os.Getpid())

if !isUNIXSocket && !isListenPID {
server.Addr = listenAddr
}

shouldAddServer := true

switch {
case os.Getenv("LISTEN_PID") == strconv.Itoa(os.Getpid()):
case isListenPID:
if i == 0 {
slog.Info("Starting server using systemd socket for the first listen address", slog.String("address_info", listenAddr))
startSystemdSocketServer(server)
} else {
slog.Warn("Systemd socket activation: Only the first listen address is used by systemd. Other addresses ignored.", slog.String("skipped_address", listenAddr))
shouldAddServer = false
slog.Warn("Systemd socket activation: Only the first listen address is used by systemd. Other addresses are ignored.", slog.String("skipped_address", listenAddr))
continue
}
case strings.HasPrefix(listenAddr, "/"): // Unix socket
case isUNIXSocket:
startUnixSocketServer(server, listenAddr)
case certDomain != "" && (listenAddr == ":https" || (i == 0 && strings.Contains(listenAddr, ":"))):
server.Addr = listenAddr
Expand All @@ -101,9 +101,7 @@ func StartWebServer(store *storage.Storage, pool *worker.Pool) []*http.Server {
startHTTPServer(server)
}

if shouldAddServer {
httpServers = append(httpServers, server)
}
httpServers = append(httpServers, server)
}

return httpServers
Expand Down Expand Up @@ -250,10 +248,6 @@ func setupHandler(store *storage.Storage, pool *worker.Pool) *mux.Router {

subrouter.HandleFunc("/healthcheck", readinessProbe).Name("healthcheck")

subrouter.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(version.Version))
}).Name("version")

if config.Opts.HasMetricsCollector() {
subrouter.Handle("/metrics", promhttp.Handler()).Name("metrics")
subrouter.Use(func(next http.Handler) http.Handler {
Expand Down
4 changes: 4 additions & 0 deletions internal/reader/encoding/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ func NewCharsetReader(r io.Reader, contentType string) (io.Reader, error) {
return nil, fmt.Errorf(`encoding: unable to read input: %w`, err)
}

return NewCharsetReaderFromBytes(buffer, contentType)
}

func NewCharsetReaderFromBytes(buffer []byte, contentType string) (io.Reader, error) {
internalReader := bytes.NewReader(buffer)

// The document is already UTF-8, do not do anything.
Expand Down
23 changes: 13 additions & 10 deletions internal/reader/subscription/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ package subscription // import "miniflux.app/v2/internal/reader/subscription"

import (
"bytes"
"io"
"log/slog"
"net/url"
"strings"
Expand Down Expand Up @@ -71,7 +70,7 @@ func (f *subscriptionFinder) FindSubscriptions(websiteURL, rssBridgeURL string,

// Step 2) Find the canonical URL of the website.
slog.Debug("Try to find the canonical URL of the website", slog.String("website_url", websiteURL))
websiteURL = f.findCanonicalURL(websiteURL, responseHandler.ContentType(), bytes.NewReader(responseBody))
websiteURL = f.findCanonicalURL(websiteURL, responseHandler.ContentType(), responseBody)

// Step 3) Check if the website URL is a YouTube channel.
slog.Debug("Try to detect feeds for a YouTube page", slog.String("website_url", websiteURL))
Expand All @@ -87,7 +86,7 @@ func (f *subscriptionFinder) FindSubscriptions(websiteURL, rssBridgeURL string,
slog.String("website_url", websiteURL),
slog.String("content_type", responseHandler.ContentType()),
)
if subscriptions, localizedError := f.findSubscriptionsFromWebPage(websiteURL, responseHandler.ContentType(), bytes.NewReader(responseBody)); localizedError != nil {
if subscriptions, localizedError := f.findSubscriptionsFromWebPage(websiteURL, responseHandler.ContentType(), responseBody); localizedError != nil {
return nil, localizedError
} else if len(subscriptions) > 0 {
slog.Debug("Subscriptions found from web page", slog.String("website_url", websiteURL), slog.Any("subscriptions", subscriptions))
Expand Down Expand Up @@ -117,14 +116,14 @@ func (f *subscriptionFinder) FindSubscriptions(websiteURL, rssBridgeURL string,
return nil, nil
}

func (f *subscriptionFinder) findSubscriptionsFromWebPage(websiteURL, contentType string, body io.Reader) (Subscriptions, *locale.LocalizedErrorWrapper) {
func (f *subscriptionFinder) findSubscriptionsFromWebPage(websiteURL, contentType string, body []byte) (Subscriptions, *locale.LocalizedErrorWrapper) {
queries := map[string]string{
"link[type='application/rss+xml']": parser.FormatRSS,
"link[type='application/atom+xml']": parser.FormatAtom,
"link[type='application/json'], link[type='application/feed+json']": parser.FormatJSON,
}

htmlDocumentReader, err := encoding.NewCharsetReader(body, contentType)
htmlDocumentReader, err := encoding.NewCharsetReaderFromBytes(body, contentType)
if err != nil {
return nil, locale.NewLocalizedErrorWrapper(err, "error.unable_to_parse_html_document", err)
}
Expand All @@ -143,12 +142,16 @@ func (f *subscriptionFinder) findSubscriptionsFromWebPage(websiteURL, contentTyp

var subscriptions Subscriptions
subscriptionURLs := make(map[string]bool)
for query, kind := range queries {
doc.Find(query).Each(func(i int, s *goquery.Selection) {
for feedQuerySelector, feedFormat := range queries {
doc.Find(feedQuerySelector).Each(func(i int, s *goquery.Selection) {
subscription := new(subscription)
subscription.Type = kind
subscription.Type = feedFormat

if feedURL, exists := s.Attr("href"); exists && feedURL != "" {
// Ignore JSON feed URLs that contain "wp-json" to avoid confusion with WordPress REST API endpoints.
if feedFormat == parser.FormatJSON && strings.Contains(feedURL, "wp-json") {
return
}
subscription.URL, err = urllib.ResolveToAbsoluteURL(websiteURL, feedURL)
if err != nil {
return
Expand Down Expand Up @@ -323,8 +326,8 @@ func (f *subscriptionFinder) findSubscriptionsFromYouTube(websiteURL string) (Su

// findCanonicalURL extracts the canonical URL from the HTML <link rel="canonical"> tag.
// Returns the canonical URL if found, otherwise returns the effective URL.
func (f *subscriptionFinder) findCanonicalURL(effectiveURL, contentType string, body io.Reader) string {
htmlDocumentReader, err := encoding.NewCharsetReader(body, contentType)
func (f *subscriptionFinder) findCanonicalURL(effectiveURL, contentType string, body []byte) string {
htmlDocumentReader, err := encoding.NewCharsetReaderFromBytes(body, contentType)
if err != nil {
return effectiveURL
}
Expand Down
47 changes: 34 additions & 13 deletions internal/reader/subscription/finder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package subscription

import (
"strings"
"testing"
)

Expand Down Expand Up @@ -120,7 +119,7 @@ func TestParseWebPageWithRssFeed(t *testing.T) {
</body>
</html>`

subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", strings.NewReader(htmlPage))
subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", []byte(htmlPage))
if err != nil {
t.Fatalf(`Parsing a correctly formatted HTML page should not return any error: %v`, err)
}
Expand Down Expand Up @@ -153,7 +152,7 @@ func TestParseWebPageWithAtomFeed(t *testing.T) {
</body>
</html>`

subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", strings.NewReader(htmlPage))
subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", []byte(htmlPage))
if err != nil {
t.Fatalf(`Parsing a correctly formatted HTML page should not return any error: %v`, err)
}
Expand Down Expand Up @@ -186,7 +185,7 @@ func TestParseWebPageWithJSONFeed(t *testing.T) {
</body>
</html>`

subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", strings.NewReader(htmlPage))
subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", []byte(htmlPage))
if err != nil {
t.Fatalf(`Parsing a correctly formatted HTML page should not return any error: %v`, err)
}
Expand Down Expand Up @@ -219,7 +218,7 @@ func TestParseWebPageWithOldJSONFeedMimeType(t *testing.T) {
</body>
</html>`

subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", strings.NewReader(htmlPage))
subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", []byte(htmlPage))
if err != nil {
t.Fatalf(`Parsing a correctly formatted HTML page should not return any error: %v`, err)
}
Expand All @@ -241,6 +240,28 @@ func TestParseWebPageWithOldJSONFeedMimeType(t *testing.T) {
}
}

func TestParseWebPageWithJSONFeedWpJsonIgnored(t *testing.T) {
htmlPage := `
<!doctype html>
<html>
<head>
<link rel="https://api.w.org/" href="https://example.org/wp-json/" />
<link rel="alternate" title="JSON" type="application/json" href="https://example.org/wp-json/wp/v2/posts/123456" />
</head>
<body>
</body>
</html>`

subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", []byte(htmlPage))
if err != nil {
t.Fatalf(`Parsing a correctly formatted HTML page should not return any error: %v`, err)
}

if len(subscriptions) != 0 {
t.Fatal(`Incorrect number of subscriptions returned`)
}
}

func TestParseWebPageWithRelativeFeedURL(t *testing.T) {
htmlPage := `
<!doctype html>
Expand All @@ -252,7 +273,7 @@ func TestParseWebPageWithRelativeFeedURL(t *testing.T) {
</body>
</html>`

subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", strings.NewReader(htmlPage))
subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", []byte(htmlPage))
if err != nil {
t.Fatalf(`Parsing a correctly formatted HTML page should not return any error: %v`, err)
}
Expand Down Expand Up @@ -285,7 +306,7 @@ func TestParseWebPageWithEmptyTitle(t *testing.T) {
</body>
</html>`

subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", strings.NewReader(htmlPage))
subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", []byte(htmlPage))
if err != nil {
t.Fatalf(`Parsing a correctly formatted HTML page should not return any error: %v`, err)
}
Expand Down Expand Up @@ -319,7 +340,7 @@ func TestParseWebPageWithMultipleFeeds(t *testing.T) {
</body>
</html>`

subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", strings.NewReader(htmlPage))
subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", []byte(htmlPage))
if err != nil {
t.Fatalf(`Parsing a correctly formatted HTML page should not return any error: %v`, err)
}
Expand All @@ -341,7 +362,7 @@ func TestParseWebPageWithDuplicatedFeeds(t *testing.T) {
</body>
</html>`

subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", strings.NewReader(htmlPage))
subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", []byte(htmlPage))
if err != nil {
t.Fatalf(`Parsing a correctly formatted HTML page should not return any error: %v`, err)
}
Expand Down Expand Up @@ -374,7 +395,7 @@ func TestParseWebPageWithEmptyFeedURL(t *testing.T) {
</body>
</html>`

subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", strings.NewReader(htmlPage))
subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", []byte(htmlPage))
if err != nil {
t.Fatalf(`Parsing a correctly formatted HTML page should not return any error: %v`, err)
}
Expand All @@ -395,7 +416,7 @@ func TestParseWebPageWithNoHref(t *testing.T) {
</body>
</html>`

subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", strings.NewReader(htmlPage))
subscriptions, err := NewSubscriptionFinder(nil).findSubscriptionsFromWebPage("http://example.org/", "text/html", []byte(htmlPage))
if err != nil {
t.Fatalf(`Parsing a correctly formatted HTML page should not return any error: %v`, err)
}
Expand All @@ -416,7 +437,7 @@ func TestFindCanonicalURL(t *testing.T) {
</body>
</html>`

canonicalURL := NewSubscriptionFinder(nil).findCanonicalURL("https://example.org/page", "text/html", strings.NewReader(htmlPage))
canonicalURL := NewSubscriptionFinder(nil).findCanonicalURL("https://example.org/page", "text/html", []byte(htmlPage))
if canonicalURL != "https://example.org/canonical-page" {
t.Errorf(`Unexpected canonical URL, got %q, expected %q`, canonicalURL, "https://example.org/canonical-page")
}
Expand All @@ -432,7 +453,7 @@ func TestFindCanonicalURLNotFound(t *testing.T) {
</body>
</html>`

canonicalURL := NewSubscriptionFinder(nil).findCanonicalURL("https://example.org/page", "text/html", strings.NewReader(htmlPage))
canonicalURL := NewSubscriptionFinder(nil).findCanonicalURL("https://example.org/page", "text/html", []byte(htmlPage))
if canonicalURL != "https://example.org/page" {
t.Errorf(`Expected effective URL when canonical not found, got %q`, canonicalURL)
}
Expand Down
Loading
0