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:
ShenLin
2026-08-29 01:10:01 +08:00
committed by GitHub
parent 3943180898
commit 31ae0f5bc9
2 changed files with 75 additions and 24 deletions
+28 -23
View File
@@ -2,7 +2,6 @@ package onedrive_sharelink
import (
"context"
"crypto/tls"
"encoding/json"
"fmt"
"io"
@@ -13,30 +12,28 @@ import (
"time"
"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"
"golang.org/x/net/html"
)
// NewNoRedirectClient creates an HTTP client that doesn't follow redirects
func NewNoRedirectCLient() *http.Client {
return &http.Client{
Timeout: time.Hour * 48,
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 {
client := internalNet.NewHttpClient()
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
return client
}
// 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
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 {
return "", err
}
@@ -95,16 +92,18 @@ func getCookiesWithPassword(link, password string) (string, error) {
"__VIEWSTATEENCRYPTED": []string{""},
}
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
client := NewNoRedirectCLient()
// 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 {
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
cookie := resp.Cookies()
@@ -153,6 +152,7 @@ func (d *OnedriveSharelink) getHeaders(ctx context.Context) (http.Header, error)
if err != nil {
return nil, err
}
defer answerNoRedirect.Body.Close()
redirectUrl := answerNoRedirect.Header.Get("Location")
log.Debugln("redirectUrl:", redirectUrl)
if redirectUrl == "" {
@@ -169,7 +169,7 @@ func (d *OnedriveSharelink) getHeaders(ctx context.Context) (http.Header, error)
header.Set("authority", u.Host)
return header, nil
} else {
cookie, err := getCookiesWithPassword(d.ShareLinkURL, d.ShareLinkPassword)
cookie, err := getCookiesWithPassword(ctx, d.ShareLinkURL, d.ShareLinkPassword)
if err != nil {
return nil, err
}
@@ -197,6 +197,7 @@ func (d *OnedriveSharelink) getFiles(ctx context.Context, path string) ([]Item,
if err != nil {
return nil, err
}
_ = answerNoRedirect.Body.Close()
redirectUrl = answerNoRedirect.Header.Get("Location")
} else {
header = d.Headers
@@ -205,6 +206,7 @@ func (d *OnedriveSharelink) getFiles(ctx context.Context, path string) ([]Item,
if err != nil {
return nil, err
}
_ = answerNoRedirect.Body.Close()
redirectUrl = answerNoRedirect.Header.Get("Location")
}
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"}
client := &http.Client{}
client := base.HttpClient
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 {
return nil, err
}
@@ -326,7 +328,10 @@ func (d *OnedriveSharelink) getFiles(ctx context.Context, path string) ([]Item,
log.Debugln("nextHref:", nextHref)
graphqlReqNEW := GraphQLNEWRequest{}
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
resp, err := client.Do(req)
+46
View File
@@ -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")
}
}