couchbase / sync_gateway

Manages access and synchronization between Couchbase Lite and Couchbase Server
https://www.couchbase.com/products/sync-gateway
Other
448 stars 138 forks source link

Cannot PUT _local documents when "/" is encoded as "%2F" #324

Closed stemail23 closed 9 years ago

stemail23 commented 10 years ago

_(See https://groups.google.com/forum/?utm_source=footer#!topic/mobile-couchbase/b3ZFu_CdnAc for discussion leading to issue report.)_

Attempts to PUT documents on the sync gateway REST api fail if the document id contains a slash character encoded as %2f. The same attempt succeeds if the document id contains a slash character that is not encoded. Thus:

This succeeds: curl -X PUT http://localhost:4985/tests/_local/tester --data '{"foo": "bar"}' -H "content-type:application/json"

whereas this fails (404 response): curl -X PUT http://localhost:4985/tests/_local%2Ftester --data '{"foo": "bar"}' -H "content-type:application/json"

In couchDB, both formats succeed. The same situation occurs when attempting to GET a document containing an encoded slash in the id.

snej commented 10 years ago

I'm pretty certain this only applies to local docs, i.e. where the doc ID begins with _local/. These are routed differently than regular docs.

ajres commented 10 years ago

Reading http://tools.ietf.org/html/rfc3986, it does not appear that the following paths are equivalent:

/tests/_local/tester

and

/tests/_local%2Ftester

section-2.4 states that the components and sub-components of a URI are separated before decoding.

So in example 2 above I think the the path refers to a document "_local/tester" in database "test"

Which would suggest that the sync_gateway behaviour is correct?

snej commented 10 years ago

They are different URLs, but equivalent in the CouchDB API. I believe the second one is the canonical path, since it’s a single document within a database that happens to have a “/“ in its name; but as a convenience the server accepts the first form as equivalent. The Gateway’s URL routing happens to accept only the first form.

ajres commented 10 years ago

The only way I have found to do this so far is to add additional handlers for the encoded '/' characters.

routing.go has been modified as follows:

// Document URLs:
    dbr.Handle("/_local/{docid}", makeHandler(sc, privs, (*handler).handleGetLocalDoc)).Methods("GET", "HEAD")
    dbr.Handle("/_local%2F{docid}", makeHandler(sc, privs, (*handler).handleGetLocalDoc)).Methods("GET", "HEAD")
    dbr.Handle("/_local%2f{docid}", makeHandler(sc, privs, (*handler).handleGetLocalDoc)).Methods("GET", "HEAD")
    dbr.Handle("/_local/{docid}", makeHandler(sc, privs, (*handler).handlePutLocalDoc)).Methods("PUT")
    dbr.Handle("/_local%2F{docid}", makeHandler(sc, privs, (*handler).handlePutLocalDoc)).Methods("PUT")
    dbr.Handle("/_local%2f{docid}", makeHandler(sc, privs, (*handler).handlePutLocalDoc)).Methods("PUT")
    dbr.Handle("/_local/{docid}", makeHandler(sc, privs, (*handler).handleDelLocalDoc)).Methods("DELETE")
    dbr.Handle("/_local%2F{docid}", makeHandler(sc, privs, (*handler).handleDelLocalDoc)).Methods("DELETE")
    dbr.Handle("/_local%2f{docid}", makeHandler(sc, privs, (*handler).handleDelLocalDoc)).Methods("DELETE")

I did try using a regex to match multiple patterns but this results in bad docid values being passed to the Handler, I think this is the same issue as described here.

tleyden commented 9 years ago

Re-opening per https://github.com/couchbase/sync_gateway/issues/324#ref-issue-45068650

tleyden commented 9 years ago

Closing #442 as duplicate .. re-opening this since it has a better description of problem.

The fix for #324 implemented in #384 does not cover the equivalent issue for other underscore prefixed document ids (e.g. _user and _role etc.)

snej commented 9 years ago

Document IDs can't begin with an underscore. Underscores are reserved for special endpoints like _changes or _user, etc.