diff --git a/channels/shangwutong/internal/swt/client.go b/channels/shangwutong/internal/swt/client.go index 543166a5..3228bd58 100644 --- a/channels/shangwutong/internal/swt/client.go +++ b/channels/shangwutong/internal/swt/client.go @@ -197,13 +197,18 @@ func (c *Client) sendHTML(ctx context.Context, session Session, sid, content, op } return SendResult{}, &Error{Operation: operation, Code: "network_error", Retryable: true, Err: err} } - status := response.Header.Get("r") + status := strings.TrimSpace(response.Header.Get("r")) + if !strings.EqualFold(status, "ok") { + if protocolError := strings.TrimSpace(response.Header.Get("error")); protocolError != "" { + status = protocolError + } + } result := SendResult{Status: status, Body: body} - if status == "ok" { + if strings.EqualFold(status, "ok") { return result, nil } - retryable := status == "server err" - return result, &Error{Operation: operation, Code: normalizeCode(status), Retryable: retryable} + code := normalizeCode(status) + return result, &Error{Operation: operation, Code: code, Retryable: code == "server_err"} } func (c *Client) SetPresence(ctx context.Context, session Session, presence Presence) error { diff --git a/channels/shangwutong/internal/swt/client_test.go b/channels/shangwutong/internal/swt/client_test.go index 765c8965..02e8a851 100644 --- a/channels/shangwutong/internal/swt/client_test.go +++ b/channels/shangwutong/internal/swt/client_test.go @@ -68,6 +68,40 @@ func TestClientSendTextEscapesHTML(t *testing.T) { } } +func TestClientSendTextClassifiesProtocolStatus(t *testing.T) { + tests := []struct { + name, status, protocolError, wantCode string + wantRetryable bool + }{ + {name: "success", status: "ok"}, + {name: "explicit failure", status: "failed", wantCode: "failed"}, + {name: "error header", protocolError: "state err", wantCode: "state_err"}, + {name: "retryable error", protocolError: "server err", wantCode: "server_err", wantRetryable: true}, + {name: "missing status", wantCode: "missing_status"}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(response http.ResponseWriter, _ *http.Request) { + response.Header().Set("r", test.status) + response.Header().Set("error", test.protocolError) + })) + defer server.Close() + + result, err := NewClient(rewriteTransportClient(server.URL)).SendText(context.Background(), testSession(), "sid", "hello") + if test.wantCode == "" { + if err != nil || result.Status != "ok" { + t.Fatalf("result = %#v, error = %v", result, err) + } + return + } + var protocolErr *Error + if !errors.As(err, &protocolErr) || protocolErr.Code != test.wantCode || protocolErr.Retryable != test.wantRetryable { + t.Fatalf("result = %#v, error = %#v", result, err) + } + }) + } +} + func TestClientSendFailureBeforeRequestWriteIsRetryable(t *testing.T) { client := NewClient(&http.Client{Transport: roundTripFunc(func(*http.Request) (*http.Response, error) { return nil, errors.New("connection lost")