jcoglan commented on PR #5858:
URL: https://github.com/apache/couchdb/pull/5858#issuecomment-4562936096

   Been looking into how the errors should be passed from `mango_native_proc` 
back to the client and how this affects the use of `{forbidden, _}` tuples.
   
   Many places in the codebase throw or catch (or otherwise create/use) the 
structure `{forbidden, Msg}`. `forbidden` is an atom and `Msg` is usually a 
binary, though it can be a string, a list (e.g. `["by_node not an object"]`) or 
a tuple (e.g. `chttpd_auth_request` throws `{forbidden, {Error, Reason}}`).
   
   The specific code path for VDUs is that the actual VDU engine (a JS process 
or `mango_native_proc`) throws a JS object like `{ forbidden: Msg }`, which is 
`{[{<<"forbidden">>, Msg}]}` in Erlang. 
`couch_query_servers:validate_doc_update()` catches `{[{<<"forbidden">>, 
Msg}]}` and converts it into `{forbidden, Msg}` i.e. a normal Erlang pair with 
`forbidden` as an atom. This is re-thrown and passed back through fabric and 
other request-handling machinery until it ends up in the HTTP layer.
   
   `chttpd` has two handlers relevant here:
   
   - `error_info({forbidden, Msg})` produces a 403 response with `{ "error": 
"forbidden", "reason": Msg }`
   - `error_info({forbidden, Error, Msg})` produces a 403 response with `{ 
"error": Error, "reason": Msg }`
   
   The problem we have is: how to send the list of failure objects from 
`mango_native_proc` back to the client. The current design means it's safe for 
`couch_query_servers` to throw a 3-tuple and `chttpd` will be able to handle 
it, so there's no problem there vis-a-vis rolling upgrades. However, this only 
lets us change the `error` field in the response, whereas we probably want to 
keep `"error": "forbidden"` as the response for failed Mango VDU validations.
   
   If we have `couch_query_servers` throw the 2-tuple `{forbidden, 
{[{<<"failures">>, Failures}]}}` (`Failures` is the list of validation 
failures) then this ends up putting the failures in the `reason` field of the 
response, e.g.:
   
   ```json
   {
     "error": "forbidden",
     "reason": {
       "failures": [
         {
           "path": ["newDoc", "ok"],
           "message": "must be present"
         }
       ]
     }
   }
   ```
   
   Technically, this is not a breaking change; it was already legal for a JS 
VDU to throw `{ forbidden: { failures: [...] } }` and this would end producing 
the response above. However there has been concern that making `reason` not be 
a string would be surprising to most users and could break existing programs, 
so should be considered a breaking change.
   
   If we want to retain `reason` as a string and put the `failures` list 
somewhere else then we need to invent some other way for `couch_query_servers` 
to throw an error message and failure list, and put these into the HTTP 
response. One such way is to make it throw `{forbidden, {failures, Failures}}`, 
and then make `chttpd:send_error()` inspect `ReasonStr`. If it's `{failures, 
Failures}` then we make it put this in the response:
   
   ```json
     "reason": "document is not valid",
     "failures": Failures
   ```
   
   Otherwise we make it just emit `"reason": ReasonStr` as it currently does. 
The problem with this is that it couples some generic HTTP error handling code 
to the specifics of VDUs, which seems like a bad idea. We could weaken this 
coupling by making `couch_query_servers` throw a more complex object containing 
the `reason` and any additional fields, and make `send_error()` emit all that 
data into the response, i.e. it lets `ReasonStr` be either a string, or a set 
of JSON fields. This removes the coupling but still adds some complexity to how 
errors are communicated.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to