aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAKP <tom@tdpain.net>2023-01-19 17:35:21 +0000
committerAKP <tom@tdpain.net>2023-01-19 17:35:21 +0000
commitcd1c867e10f3faaac844888272741460c5b3622e (patch)
tree6fc75e764398c4d711a5f9f4bde256848b924134
parent4a3458b9a8e9113f4f6c2159da66b3385feac6c5 (diff)
Support Last-Modified header
Signed-off-by: AKP <tom@tdpain.net>
-rw-r--r--walrss/internal/db/20230119135807_etags.go2
-rw-r--r--walrss/internal/db/20230119165107_lastmodified.go34
-rw-r--r--walrss/internal/db/db.go8
-rw-r--r--walrss/internal/rss/processor.go29
4 files changed, 62 insertions, 11 deletions
diff --git a/walrss/internal/db/20230119135807_etags.go b/walrss/internal/db/20230119135807_etags.go
index dd34934..478d070 100644
--- a/walrss/internal/db/20230119135807_etags.go
+++ b/walrss/internal/db/20230119135807_etags.go
@@ -38,7 +38,7 @@ func init() {
for _, query := range queries {
if _, err := db.ExecContext(ctx, query); err != nil {
- if !strings.Contains(err.Error(), "no such column2") {
+ if !strings.Contains(err.Error(), "no such column") {
return err
}
}
diff --git a/walrss/internal/db/20230119165107_lastmodified.go b/walrss/internal/db/20230119165107_lastmodified.go
new file mode 100644
index 0000000..109ff25
--- /dev/null
+++ b/walrss/internal/db/20230119165107_lastmodified.go
@@ -0,0 +1,34 @@
+package db
+
+import (
+ "context"
+ "github.com/uptrace/bun"
+ "strings"
+)
+
+func init() {
+ migs.MustRegister(
+ func(ctx context.Context, db *bun.DB) error {
+ migLogger.Debug().Msg("2022-01-19@16:51:07 up")
+
+ if _, err := db.ExecContext(ctx, `ALTER TABLE feeds ADD COLUMN last_modified VARCHAR;`); err != nil {
+ if !strings.Contains(err.Error(), "duplicate column name") {
+ return err
+ }
+ }
+
+ return nil
+ },
+ func(ctx context.Context, db *bun.DB) error {
+ migLogger.Debug().Msg("2022-01-19@16:51:07 down")
+
+ if _, err := db.ExecContext(ctx, `ALTER TABLE feeds DROP COLUMN last_modified;`); err != nil {
+ if !strings.Contains(err.Error(), "no such column") {
+ return err
+ }
+ }
+
+ return nil
+ },
+ )
+}
diff --git a/walrss/internal/db/db.go b/walrss/internal/db/db.go
index 6ee09cb..604ef91 100644
--- a/walrss/internal/db/db.go
+++ b/walrss/internal/db/db.go
@@ -44,16 +44,24 @@ type Feed struct {
UserID string `bun:"user_id,notnull"`
LastEtag string `bun:"last_etag,nullzero"`
+ LastModified string `bun:"last_modified,nullzero"`
CachedContent string `bun:"cached_content,nullzero"`
User *User `bun:",rel:belongs-to,join:user_id=id"`
}
func (f *Feed) CacheWithEtag(etag, content string) {
+ f.LastModified = ""
f.LastEtag = etag
f.CachedContent = content
}
+func (f *Feed) CacheWithLastModified(lastModified, content string) {
+ f.LastEtag = ""
+ f.LastModified = lastModified
+ f.CachedContent = content
+}
+
type FeedSlice []*Feed
func (f FeedSlice) Len() int {
diff --git a/walrss/internal/rss/processor.go b/walrss/internal/rss/processor.go
index fcef386..947d98c 100644
--- a/walrss/internal/rss/processor.go
+++ b/walrss/internal/rss/processor.go
@@ -174,7 +174,7 @@ func getFeedContent(st *state.State, f *db.Feed) (*gofeed.Feed, error) {
requestBuilder := requests.URL(f.URL).ToBytesBuffer(buf).UserAgent(getUserAgent(st)).CopyHeaders(headers)
- if f.LastEtag != "" {
+ if f.LastEtag != "" || f.LastModified != "" {
requestBuilder.AddValidator(
func(resp *http.Response) error {
if resp.StatusCode == http.StatusNotModified {
@@ -185,7 +185,13 @@ func getFeedContent(st *state.State, f *db.Feed) (*gofeed.Feed, error) {
}
},
)
- requestBuilder.Header("If-None-Match", f.LastEtag)
+
+ if f.LastEtag != "" {
+ requestBuilder.Header("If-None-Match", f.LastEtag)
+ } else if f.LastModified != "" {
+ requestBuilder.Header("If-Modified-Since", f.LastModified)
+ }
+
} else {
requestBuilder.AddValidator(requests.DefaultValidator) // Since we're using CopyHeaders, we need to add the
// default validator back ourselves.
@@ -198,14 +204,17 @@ func getFeedContent(st *state.State, f *db.Feed) (*gofeed.Feed, error) {
if notModified {
log.Debug().Msgf("%s not modified", f.URL)
buf.WriteString(f.CachedContent)
- } else {
- log.Debug().Msgf("%s modified", f.URL)
- etag := headers.Get("ETag")
- if etag != "" {
- f.CacheWithEtag(etag, buf.String())
- if err := core.UpdateFeed(st, f); err != nil {
- return nil, fmt.Errorf("failed to cache ETag-ed response: %v", err)
- }
+ } else if etag := headers.Get("ETag"); etag != "" {
+ log.Debug().Msgf("%s modified (ETag)", f.URL)
+ f.CacheWithEtag(etag, buf.String())
+ if err := core.UpdateFeed(st, f); err != nil {
+ return nil, fmt.Errorf("failed to cache ETag-ed response: %v", err)
+ }
+ } else if lastModified := headers.Get("Last-Modified"); lastModified != "" {
+ log.Debug().Msgf("%s modified (Last-Modified)", f.URL)
+ f.CacheWithLastModified(lastModified, buf.String())
+ if err := core.UpdateFeed(st, f); err != nil {
+ return nil, fmt.Errorf("failed to cache Last-Modified enabled response: %v", err)
}
}