rc: respond with 202 if prefer-async header is passed
Make rc respond with a 202 status code (instead of 200) if `Prefer: respond- async` was passed. Keeps backwards compatibility for current clients while also allowing the OpenAPI schema & generators to differentiate the responses properly.
This commit is contained in:
@@ -267,6 +267,13 @@ It is recommended that potentially long running jobs, e.g. `sync/sync`,
|
||||
flag to avoid any potential problems with the HTTP request and
|
||||
response timing out.
|
||||
|
||||
As an alternative to `_async`, you can send the HTTP header
|
||||
`Prefer: respond-async` (RFC 7240). This has the same effect as
|
||||
`_async = true` but additionally returns HTTP status 202 (Accepted)
|
||||
instead of 200, and includes a `Preference-Applied: respond-async`
|
||||
response header. The 202 status code makes it easy for clients to distinguish
|
||||
an async response from a completed one without inspecting the body.
|
||||
|
||||
Starting a job with the `_async` flag:
|
||||
|
||||
```console
|
||||
|
||||
@@ -257,6 +257,17 @@ func (s *Server) handlePost(w http.ResponseWriter, r *http.Request, path string)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Check for Prefer: respond-async header (RFC 7240)
|
||||
preferAsync := false
|
||||
for _, pref := range strings.Split(r.Header.Get("Prefer"), ",") {
|
||||
if strings.EqualFold(strings.TrimSpace(pref), "respond-async") {
|
||||
preferAsync = true
|
||||
in["_async"] = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Find the call
|
||||
call := rc.Calls.Get(path)
|
||||
if call == nil {
|
||||
@@ -296,6 +307,10 @@ func (s *Server) handlePost(w http.ResponseWriter, r *http.Request, path string)
|
||||
|
||||
fs.Debugf(nil, "rc: %q: reply %+v: %v", path, out, err)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if preferAsync {
|
||||
w.Header().Set("Preference-Applied", "respond-async")
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
err = rc.WriteJSON(w, out)
|
||||
if err != nil {
|
||||
// can't return the error at this point - but have a go anyway
|
||||
|
||||
@@ -89,18 +89,19 @@ func TestRcServer(t *testing.T) {
|
||||
}
|
||||
|
||||
type testRun struct {
|
||||
Name string
|
||||
URL string
|
||||
User string
|
||||
Pass string
|
||||
Status int
|
||||
Method string
|
||||
Range string
|
||||
Body string
|
||||
ContentType string
|
||||
Expected string
|
||||
Contains *regexp.Regexp
|
||||
Headers map[string]string
|
||||
Name string
|
||||
URL string
|
||||
User string
|
||||
Pass string
|
||||
Status int
|
||||
Method string
|
||||
Range string
|
||||
Body string
|
||||
ContentType string
|
||||
Expected string
|
||||
Contains *regexp.Regexp
|
||||
Headers map[string]string
|
||||
RequestHeaders map[string]string
|
||||
}
|
||||
|
||||
// Run a suite of tests
|
||||
@@ -144,6 +145,9 @@ func emulateCalls(t *testing.T, tests []testRun, mux chi.Router, testURL string)
|
||||
if test.User != "" && test.Pass != "" {
|
||||
req.SetBasicAuth(test.User, test.Pass)
|
||||
}
|
||||
for k, v := range test.RequestHeaders {
|
||||
req.Header.Set(k, v)
|
||||
}
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
@@ -794,6 +798,33 @@ func TestRCAsync(t *testing.T) {
|
||||
Body: `{ "_async":true }`,
|
||||
Status: http.StatusOK,
|
||||
Contains: regexp.MustCompile(`(?s)\{.*\"jobid\":.*\}`),
|
||||
}, {
|
||||
Name: "prefer-respond-async",
|
||||
URL: "rc/noop",
|
||||
Method: "POST",
|
||||
ContentType: "application/json",
|
||||
Body: `{ "_async":true }`,
|
||||
RequestHeaders: map[string]string{"Prefer": "respond-async"},
|
||||
Status: http.StatusAccepted,
|
||||
Contains: regexp.MustCompile(`(?s)\{.*\"jobid\":.*\}`),
|
||||
}, {
|
||||
Name: "prefer-without-async",
|
||||
URL: "rc/noop",
|
||||
Method: "POST",
|
||||
ContentType: "application/json",
|
||||
Body: `{}`,
|
||||
RequestHeaders: map[string]string{"Prefer": "respond-async"},
|
||||
Status: http.StatusAccepted,
|
||||
Contains: regexp.MustCompile(`(?s)\{.*\"jobid\":.*\}`),
|
||||
}, {
|
||||
Name: "prefer-respond-async-mixed",
|
||||
URL: "rc/noop",
|
||||
Method: "POST",
|
||||
ContentType: "application/json",
|
||||
Body: `{}`,
|
||||
RequestHeaders: map[string]string{"Prefer": "wait=10, respond-async"},
|
||||
Status: http.StatusAccepted,
|
||||
Contains: regexp.MustCompile(`(?s)\{.*\"jobid\":.*\}`),
|
||||
}, {
|
||||
Name: "bad",
|
||||
URL: "rc/noop",
|
||||
|
||||
Reference in New Issue
Block a user