mirror of
https://github.com/OpenListTeam/OpenList.git
synced 2026-10-10 04:53:09 +08:00
fix(drivers/onedrive_sharelink): reuse shared HTTP clients (#2961)
fix(onedrive_sharelink): reuse shared HTTP clients - Reuse shared client settings for redirect and GraphQL requests - Propagate request contexts through password and pagination requests - Close OneDrive response bodies that were missing cleanup - Add tests for shared client settings and redirect handling Signed-off-by: jyxjjj <16695261+jyxjjj@users.noreply.github.com> Co-authored-by: Codex <267193182+codex@users.noreply.github.com>
This commit is contained in:
@@ -2,7 +2,6 @@ package onedrive_sharelink
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@@ -13,30 +12,28 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/OpenListTeam/OpenList/v4/drivers/base"
|
"github.com/OpenListTeam/OpenList/v4/drivers/base"
|
||||||
"github.com/OpenListTeam/OpenList/v4/internal/conf"
|
internalNet "github.com/OpenListTeam/OpenList/v4/internal/net"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/html"
|
"golang.org/x/net/html"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewNoRedirectClient creates an HTTP client that doesn't follow redirects
|
// NewNoRedirectClient creates an HTTP client that doesn't follow redirects
|
||||||
func NewNoRedirectCLient() *http.Client {
|
func NewNoRedirectCLient() *http.Client {
|
||||||
return &http.Client{
|
client := internalNet.NewHttpClient()
|
||||||
Timeout: time.Hour * 48,
|
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
|
||||||
Transport: &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: conf.Conf.TlsInsecureSkipVerify},
|
|
||||||
},
|
|
||||||
// Prevent following redirects
|
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
||||||
return http.ErrUseLastResponse
|
return http.ErrUseLastResponse
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCookiesWithPassword fetches cookies required for authenticated access using the provided password
|
// getCookiesWithPassword fetches cookies required for authenticated access using the provided password
|
||||||
func getCookiesWithPassword(link, password string) (string, error) {
|
func getCookiesWithPassword(ctx context.Context, link, password string) (string, error) {
|
||||||
// Send GET request
|
// Send GET request
|
||||||
resp, err := http.Get(link)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, link, nil)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
resp, err := base.HttpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -95,16 +92,18 @@ func getCookiesWithPassword(link, password string) (string, error) {
|
|||||||
"__VIEWSTATEENCRYPTED": []string{""},
|
"__VIEWSTATEENCRYPTED": []string{""},
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{
|
client := NewNoRedirectCLient()
|
||||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
|
||||||
return http.ErrUseLastResponse
|
|
||||||
},
|
|
||||||
}
|
|
||||||
// Send the POST request, preventing redirects
|
// Send the POST request, preventing redirects
|
||||||
resp, err = client.PostForm(newURL, data)
|
req, err = http.NewRequestWithContext(ctx, http.MethodPost, newURL, strings.NewReader(data.Encode()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
resp, err = client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
// Extract the desired cookie value
|
// Extract the desired cookie value
|
||||||
cookie := resp.Cookies()
|
cookie := resp.Cookies()
|
||||||
@@ -153,6 +152,7 @@ func (d *OnedriveSharelink) getHeaders(ctx context.Context) (http.Header, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
defer answerNoRedirect.Body.Close()
|
||||||
redirectUrl := answerNoRedirect.Header.Get("Location")
|
redirectUrl := answerNoRedirect.Header.Get("Location")
|
||||||
log.Debugln("redirectUrl:", redirectUrl)
|
log.Debugln("redirectUrl:", redirectUrl)
|
||||||
if redirectUrl == "" {
|
if redirectUrl == "" {
|
||||||
@@ -169,7 +169,7 @@ func (d *OnedriveSharelink) getHeaders(ctx context.Context) (http.Header, error)
|
|||||||
header.Set("authority", u.Host)
|
header.Set("authority", u.Host)
|
||||||
return header, nil
|
return header, nil
|
||||||
} else {
|
} else {
|
||||||
cookie, err := getCookiesWithPassword(d.ShareLinkURL, d.ShareLinkPassword)
|
cookie, err := getCookiesWithPassword(ctx, d.ShareLinkURL, d.ShareLinkPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -197,6 +197,7 @@ func (d *OnedriveSharelink) getFiles(ctx context.Context, path string) ([]Item,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
_ = answerNoRedirect.Body.Close()
|
||||||
redirectUrl = answerNoRedirect.Header.Get("Location")
|
redirectUrl = answerNoRedirect.Header.Get("Location")
|
||||||
} else {
|
} else {
|
||||||
header = d.Headers
|
header = d.Headers
|
||||||
@@ -205,6 +206,7 @@ func (d *OnedriveSharelink) getFiles(ctx context.Context, path string) ([]Item,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
_ = answerNoRedirect.Body.Close()
|
||||||
redirectUrl = answerNoRedirect.Header.Get("Location")
|
redirectUrl = answerNoRedirect.Header.Get("Location")
|
||||||
}
|
}
|
||||||
redirectSplitURL := strings.Split(redirectUrl, "/")
|
redirectSplitURL := strings.Split(redirectUrl, "/")
|
||||||
@@ -289,9 +291,9 @@ func (d *OnedriveSharelink) getFiles(ctx context.Context, path string) ([]Item,
|
|||||||
}
|
}
|
||||||
tempHeader["Content-Type"] = []string{"application/json;odata=verbose"}
|
tempHeader["Content-Type"] = []string{"application/json;odata=verbose"}
|
||||||
|
|
||||||
client := &http.Client{}
|
client := base.HttpClient
|
||||||
postUrl := strings.Join(redirectSplitURL[:len(redirectSplitURL)-3], "/") + "/_api/v2.1/graphql"
|
postUrl := strings.Join(redirectSplitURL[:len(redirectSplitURL)-3], "/") + "/_api/v2.1/graphql"
|
||||||
req, err = http.NewRequest(http.MethodPost, postUrl, strings.NewReader(graphqlVar))
|
req, err = http.NewRequestWithContext(ctx, http.MethodPost, postUrl, strings.NewReader(graphqlVar))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -326,7 +328,10 @@ func (d *OnedriveSharelink) getFiles(ctx context.Context, path string) ([]Item,
|
|||||||
log.Debugln("nextHref:", nextHref)
|
log.Debugln("nextHref:", nextHref)
|
||||||
graphqlReqNEW := GraphQLNEWRequest{}
|
graphqlReqNEW := GraphQLNEWRequest{}
|
||||||
postUrl = strings.Join(redirectSplitURL[:len(redirectSplitURL)-3], "/") + "/_api/web/GetListUsingPath(DecodedUrl=@a1)/RenderListDataAsStream" + nextHref
|
postUrl = strings.Join(redirectSplitURL[:len(redirectSplitURL)-3], "/") + "/_api/web/GetListUsingPath(DecodedUrl=@a1)/RenderListDataAsStream" + nextHref
|
||||||
req, _ = http.NewRequest(http.MethodPost, postUrl, strings.NewReader(renderListDataAsStreamVar))
|
req, err = http.NewRequestWithContext(ctx, http.MethodPost, postUrl, strings.NewReader(renderListDataAsStreamVar))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
req.Header = tempHeader
|
req.Header = tempHeader
|
||||||
|
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package onedrive_sharelink
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
internalNet "github.com/OpenListTeam/OpenList/v4/internal/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNoRedirectClientUsesSharedSettings(t *testing.T) {
|
||||||
|
client := NewNoRedirectCLient()
|
||||||
|
sharedClient := internalNet.NewHttpClient()
|
||||||
|
if client.Timeout != sharedClient.Timeout {
|
||||||
|
t.Fatalf("expected shared timeout %s, got %s", sharedClient.Timeout, client.Timeout)
|
||||||
|
}
|
||||||
|
if reflect.TypeOf(client.Transport) != reflect.TypeOf(sharedClient.Transport) {
|
||||||
|
t.Fatalf("expected shared transport type %T, got %T", sharedClient.Transport, client.Transport)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoRedirectClientStopsRedirects(t *testing.T) {
|
||||||
|
targetRequested := false
|
||||||
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.URL.Path == "/target" {
|
||||||
|
targetRequested = true
|
||||||
|
w.WriteHeader(http.StatusNoContent)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.Redirect(w, r, "/target", http.StatusFound)
|
||||||
|
}))
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
resp, err := NewNoRedirectCLient().Get(server.URL)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if resp.StatusCode != http.StatusFound {
|
||||||
|
t.Fatalf("expected redirect response, got %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
if targetRequested {
|
||||||
|
t.Fatal("redirect target was requested")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user