Improve handling of throttled responses from Nextcloud.

This commit is contained in:
Joachim Bauch 2023-01-17 13:33:47 +01:00
parent 7bd6fdd93f
commit 5af8636573
No known key found for this signature in database
GPG key ID: 77C1D22D53E15F02
2 changed files with 59 additions and 2 deletions

View file

@ -39,6 +39,9 @@ import (
var ( var (
ErrNotRedirecting = errors.New("not redirecting to different host") ErrNotRedirecting = errors.New("not redirecting to different host")
ErrUnsupportedContentType = errors.New("unsupported_content_type") ErrUnsupportedContentType = errors.New("unsupported_content_type")
ErrIncompleteResponse = errors.New("incomplete OCS response")
ErrThrottledResponse = errors.New("throttled OCS response")
) )
type BackendClient struct { type BackendClient struct {
@ -193,8 +196,16 @@ func (b *BackendClient) PerformJSONRequest(ctx context.Context, u *url.URL, requ
return err return err
} else if ocs.Ocs == nil || ocs.Ocs.Data == nil { } else if ocs.Ocs == nil || ocs.Ocs.Data == nil {
log.Printf("Incomplete OCS response %s from %s", string(body), req.URL) log.Printf("Incomplete OCS response %s from %s", string(body), req.URL)
return fmt.Errorf("incomplete OCS response") return ErrIncompleteResponse
} else if err := json.Unmarshal(*ocs.Ocs.Data, response); err != nil { }
switch ocs.Ocs.Meta.StatusCode {
case http.StatusTooManyRequests:
log.Printf("Throttled OCS response %s from %s", string(body), req.URL)
return ErrThrottledResponse
}
if err := json.Unmarshal(*ocs.Ocs.Data, response); err != nil {
log.Printf("Could not decode OCS response body %s from %s: %s", string(*ocs.Ocs.Data), req.URL, err) log.Printf("Could not decode OCS response body %s from %s: %s", string(*ocs.Ocs.Data), req.URL, err)
return err return err
} }

View file

@ -30,6 +30,7 @@ import (
"net/http/httptest" "net/http/httptest"
"net/url" "net/url"
"reflect" "reflect"
"strings"
"testing" "testing"
"github.com/dlintw/goconf" "github.com/dlintw/goconf"
@ -47,6 +48,14 @@ func returnOCS(t *testing.T, w http.ResponseWriter, body []byte) {
Data: (*json.RawMessage)(&body), Data: (*json.RawMessage)(&body),
}, },
} }
if strings.Contains(t.Name(), "Throttled") {
response.Ocs.Meta = OcsMeta{
Status: "failure",
StatusCode: 429,
Message: "Reached maximum delay",
}
}
data, err := json.Marshal(response) data, err := json.Marshal(response)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -206,3 +215,40 @@ func TestPostOnRedirectStatusFound(t *testing.T) {
t.Errorf("Expected empty response, got %+v", response) t.Errorf("Expected empty response, got %+v", response)
} }
} }
func TestHandleThrottled(t *testing.T) {
r := mux.NewRouter()
r.HandleFunc("/ocs/v2.php/one", func(w http.ResponseWriter, r *http.Request) {
returnOCS(t, w, []byte("[]"))
})
server := httptest.NewServer(r)
defer server.Close()
u, err := url.Parse(server.URL + "/ocs/v2.php/one")
if err != nil {
t.Fatal(err)
}
config := goconf.NewConfigFile()
config.AddOption("backend", "allowed", u.Host)
config.AddOption("backend", "secret", string(testBackendSecret))
if u.Scheme == "http" {
config.AddOption("backend", "allowhttp", "true")
}
client, err := NewBackendClient(config, 1, "0.0", nil)
if err != nil {
t.Fatal(err)
}
ctx := context.Background()
request := map[string]string{
"foo": "bar",
}
var response map[string]string
err = client.PerformJSONRequest(ctx, u, request, &response)
if err == nil {
t.Error("should have triggered an error")
} else if !errors.Is(err, ErrThrottledResponse) {
t.Error(err)
}
}