mirror of
https://github.com/photoprism/photoprism.git
synced 2025-12-12 00:34:13 +01:00
WebDAV: Refactor service discovery heuristic to add custom headers #4608
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
@@ -67,7 +67,7 @@ func Discover(rawUrl, user, pass string) (result Account, err error) {
|
||||
result.AccName = serviceUrl.Host
|
||||
}
|
||||
|
||||
result.AccType = h.ServiceType
|
||||
result.AccType = h.Type
|
||||
result.AccURL = serviceUrl.String()
|
||||
|
||||
return result, nil
|
||||
|
||||
@@ -5,24 +5,34 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Headers = map[string]string
|
||||
|
||||
// Heuristic represents a heuristic for detecting a remote service type, e.g. WebDAV.
|
||||
type Heuristic struct {
|
||||
ServiceType string
|
||||
Type Type
|
||||
Domains []string
|
||||
Paths []string
|
||||
Method string
|
||||
Headers Headers
|
||||
}
|
||||
|
||||
// Heuristics for common remote service types.
|
||||
var Heuristics = []Heuristic{
|
||||
{Facebook, []string{"facebook.com", "www.facebook.com"}, []string{}, "GET"},
|
||||
{Twitter, []string{"twitter.com"}, []string{}, "GET"},
|
||||
{Flickr, []string{"flickr.com", "www.flickr.com"}, []string{}, "GET"},
|
||||
{Instagram, []string{"instagram.com", "www.instagram.com"}, []string{}, "GET"},
|
||||
{Telegram, []string{"web.telegram.org", "www.telegram.org", "telegram.org"}, []string{}, "GET"},
|
||||
{WhatsApp, []string{"web.whatsapp.com", "www.whatsapp.com", "whatsapp.com"}, []string{}, "GET"},
|
||||
{OneDrive, []string{"onedrive.live.com"}, []string{}, "GET"},
|
||||
{GDrive, []string{"drive.google.com"}, []string{}, "GET"},
|
||||
{GPhotos, []string{"photos.google.com"}, []string{}, "GET"},
|
||||
{WebDAV, []string{}, []string{"/", "/webdav/", "/originals/", "/remote.php/dav/files/{user}/", "/remote.php/webdav/", "/dav/files/{user}/", "/servlet/webdav.infostore/"}, "PROPFIND"},
|
||||
{Type: Facebook, Domains: []string{"facebook.com", "www.facebook.com"}, Paths: []string{}, Method: "GET"},
|
||||
{Type: Twitter, Domains: []string{"twitter.com"}, Paths: []string{}, Method: "GET"},
|
||||
{Type: Flickr, Domains: []string{"flickr.com", "www.flickr.com"}, Paths: []string{}, Method: "GET"},
|
||||
{Type: Instagram, Domains: []string{"instagram.com", "www.instagram.com"}, Paths: []string{}, Method: "GET"},
|
||||
{Type: Telegram, Domains: []string{"web.telegram.org", "www.telegram.org", "telegram.org"}, Paths: []string{}, Method: "GET"},
|
||||
{Type: WhatsApp, Domains: []string{"web.whatsapp.com", "www.whatsapp.com", "whatsapp.com"}, Paths: []string{}, Method: "GET"},
|
||||
{Type: OneDrive, Domains: []string{"onedrive.live.com"}, Paths: []string{}, Method: "GET"},
|
||||
{Type: GDrive, Domains: []string{"drive.google.com"}, Paths: []string{}, Method: "GET"},
|
||||
{Type: GPhotos, Domains: []string{"photos.google.com"}, Paths: []string{}, Method: "GET"},
|
||||
{Type: WebDAV,
|
||||
Domains: []string{},
|
||||
Paths: []string{"/", "/webdav/", "/originals/", "/remote.php/dav/files/{user}/", "/remote.php/webdav/", "/dav/files/{user}/", "/servlet/webdav.infostore/"},
|
||||
Method: "PROPFIND",
|
||||
Headers: Headers{"Depth": "1"},
|
||||
},
|
||||
}
|
||||
|
||||
func (h Heuristic) MatchDomain(match string) bool {
|
||||
@@ -46,14 +56,14 @@ func (h Heuristic) Discover(rawUrl, user string) *url.URL {
|
||||
return nil
|
||||
}
|
||||
|
||||
if HttpOk(h.Method, u.String()) {
|
||||
if h.TestRequest(h.Method, u.String()) {
|
||||
return u
|
||||
}
|
||||
|
||||
for _, p := range h.Paths {
|
||||
u.Path = strings.Replace(p, "{user}", user, -1)
|
||||
|
||||
if HttpOk(h.Method, u.String()) {
|
||||
if h.TestRequest(h.Method, u.String()) {
|
||||
return u
|
||||
}
|
||||
}
|
||||
|
||||
41
internal/service/request.go
Normal file
41
internal/service/request.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestRequest makes a test request to the given URL and returns true if successful.
|
||||
func (h Heuristic) TestRequest(method, rawUrl string) bool {
|
||||
req, err := http.NewRequest(method, rawUrl, nil)
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Add custom request headers:
|
||||
// https://github.com/photoprism/photoprism/pull/4608
|
||||
if len(h.Headers) > 0 {
|
||||
for key, val := range h.Headers {
|
||||
req.Header.Add(key, val)
|
||||
}
|
||||
}
|
||||
|
||||
// Create new http.Client instance.
|
||||
//
|
||||
// NOTE: Timeout specifies a time limit for requests made by
|
||||
// this Client. The timeout includes connection time, any
|
||||
// redirects, and reading the response body. The timer remains
|
||||
// running after Get, Head, Post, or Do return and will
|
||||
// interrupt reading of the Response.Body.
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
|
||||
// Send request to see if it fails.
|
||||
if resp, reqErr := client.Do(req); reqErr != nil {
|
||||
return false
|
||||
} else if resp.StatusCode < 400 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -23,48 +23,3 @@ Additional information can be found in our Developer Guide:
|
||||
<https://docs.photoprism.app/developer-guide/>
|
||||
*/
|
||||
package service
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
WebDAV = "webdav"
|
||||
Facebook = "facebook"
|
||||
Twitter = "twitter"
|
||||
Flickr = "flickr"
|
||||
Instagram = "instagram"
|
||||
Telegram = "telegram"
|
||||
WhatsApp = "whatsapp"
|
||||
GPhotos = "gphotos"
|
||||
GDrive = "gdrive"
|
||||
OneDrive = "onedrive"
|
||||
)
|
||||
|
||||
func HttpOk(method, rawUrl string) bool {
|
||||
req, err := http.NewRequest(method, rawUrl, nil)
|
||||
req.Header.Add("Depth", "1")
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Create new http.Client instance.
|
||||
//
|
||||
// NOTE: Timeout specifies a time limit for requests made by
|
||||
// this Client. The timeout includes connection time, any
|
||||
// redirects, and reading the response body. The timer remains
|
||||
// running after Get, Head, Post, or Do return and will
|
||||
// interrupt reading of the Response.Body.
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
|
||||
// Send request to see if it fails.
|
||||
if resp, err := client.Do(req); err != nil {
|
||||
return false
|
||||
} else if resp.StatusCode < 400 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
18
internal/service/types.go
Normal file
18
internal/service/types.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package service
|
||||
|
||||
// Type represents a remote service type, e.g. WebDAV.
|
||||
type Type = string
|
||||
|
||||
// Identifiers for common remote services.
|
||||
const (
|
||||
WebDAV Type = "webdav"
|
||||
Facebook Type = "facebook"
|
||||
Twitter Type = "twitter"
|
||||
Flickr Type = "flickr"
|
||||
Instagram Type = "instagram"
|
||||
Telegram Type = "telegram"
|
||||
WhatsApp Type = "whatsapp"
|
||||
GPhotos Type = "gphotos"
|
||||
GDrive Type = "gdrive"
|
||||
OneDrive Type = "onedrive"
|
||||
)
|
||||
Reference in New Issue
Block a user