before this commit, on reading data with default dict data
type is showing error to end user, without returning the
requested data.
for eg, if a read operation is triggered on model sale.order
it wont return the requested data, instead traceback is
shown in response.
in sale.order model the tax_totals field is a computed
field, with data as format default dict which was
causing the issue.
after this commit, without any traceback the requested
data will be returned to the user.
closesodoo/odoo#131123
X-original-commit: cc61b926f4daff26fb577e2f700d013ec15f4b4f
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
*: base, http_routing, mass_mailing, web, web_editor, website_slides
In some situations `werkzeug.wrappers.Response` are used instead of
`odoo.http.Reponse` that extends it.
This is a problem because since [1] the calls to `set_cookie` expect it
to accept the `cookie_type` parameter, which is not the case in the base
werkzeug implementation.
This commit replaces the `werkzeug.wrappers.Response` by
`odoo.http.Response`.
[1]: https://github.com/odoo/odoo/commit/2cbda6c98ee947cea1d06c09880eee8c758304a8closesodoo/odoo#112827
X-original-commit: 28da08292b7028575e628c5ad846fc05d30498f2
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
The new `borrow_request()` function has been introduced to properly
separate the HTTP layer from the RPC layer. We forgot to protect some
RPC endpoints, mainly inside of `odoo.addons.web.controllers.database`.
This commit moves `odoo.service.dispatch_rpc` to `odoo.http` as we only
permorm RPC from the controllers and that we don't want to import
`borrow_request` inside of `odoo.service` (circular import).
X-original-commit: d0ee8615d8820e02232989c50a6e6ffbc66a9266
Part-of: odoo/odoo#105710
Install website then render a qweb template via xmlrpc, attribute error:
`request` has no `is_frontend` attribute.
Inside the qweb's `_prepare_environment` override of the http_routing
module (a dependency of website) is the following code snippet:
if (not irQweb.env.context.get('minimal_qcontext') and
request and request.is_frontend):
return irQweb._prepare_frontend_environment(values)
The conditionnal is about injecting extra informations in the qweb's
context in case we are serving a frontend request. By default, there is
no `is_frontend` attribute on the request object. That attribute is set
by the ir.http's `_match` override of the http_routing module (a website
dependency): it is set True when we don't match any endpoint or that we
match an endpoint that is `website=True`, it is set False otherwise.
The ir.http's `_match` method is called whenever we are serving a http
request whoose session is bound to a specific database. i.e. when there
is a valid database saved in the request's session. When there is not
database in the request's session (or that it is invalid) the matched
endpoint is directly called without going throught ir.http. Most
endpoints are only accessible via ir.http.
The two `/xmlrpc` and `/jsonrpc` endpoints are examples of endpoint that
do not require an established database connection to work. They perform
the request authentication and database connection themselves. It is
possible to call those two endpoints with no database saved in the
session, thus it is possible to call those two endpoints without going
throught ir.http. This is expected.
The two endpoints's duty is to execute public model methods and return
the xml/json serialized result. To do so, a registry is loaded on the
database with all the installed modules, including http_routing.
We fall in a situation where (1) there is a request, (2) we are using a
registry where http_routing is loaded, (3) there is no `is_frontend`
attribute on `request` as we didn't serve the endpoint via ir.http. This
situation is illegale.
To solve the problem, instead of working on the `if request.is_frontend`
bit of the above conditional, we decided to work on the `if request`
bit. ISO-model wise, RPC is an extra 8th layer built on top of HTTP.
HTTP is merely a transparent transport between a RPC client and a RPC
server, any other request-response capable procotol could fit. The
method executed via RPC must be independant from the usage of HTTP as
mean of transportation thus it should not be capable of using the
current request.
The proposed change is to temporary un-expose the current request from
the local-stack during the execution of the RPC method. This fixes the
problem as the code now run like it was executed from the shell or from
a cron. The other benefit is that the pattern used inside the condition:
`if request and request.is_frontend` doesn't need to change.
X-original-commit: f28863bfdaac3f644fcb274c856e0770783ed75c
Part-of: odoo/odoo#104567
This commit is the 14th commit of a comprehensive refactor of our HTTP
framework. See odoo/odoo#78857 for complete historic, discussions and
rationnals.
* `request.uid = x` => `request.update_env(user=x)`.
* `request.context = x` => `request.update_env(context=x)`.
* `request.context = dict(request.context, x=y)`
=> `request.update_context(x=y)`.
* `request.cr = None` => `request.cr.close()`.
* `http.mono_db()` => `request.db`.
* `http.dispatch_rpc()` => `service.dispatch_rpc()`.
* `@service.model.check` => `service.model.retrying()`.
* `request.endpoint`
=> `env['ir.http']._match(request.httprequest.path)[0].endpoint`.
* `request.routing_iteration `=> `removed`.
* `request.jsonrequest` => `request.dispatcher.jsonrequest`.
Note that `request.params` is now set much later in the process. If you
are in a situation where you values from the query string or the
http body you can use `request.get_http_params()`.
Note that using the new `request.future_response`, it is possible to
add headers and cookies on the response object before the response
object is initialized. Please note that headers/cookies saved on
the future response will NOT be injected in case of error.
PR: odoo#78857
Task: 2571224
The XML-RPC interface has a compatibility shim for binaries as
historically Odoo has returned "binary" data as base64 strings. To
avoid breakages during the Python 3 transition, the shim was
introduced to decode the output binary data (under the assumption that
it'd be ASCII-compatible).
In the case where the data is *not* ascii-compatible, however, it can
generate invalid XML documents: "C0" control codes (with the exception
of tab, LF, and CR) are not valid in XML 1.0 (which XML-RPC is an
application of), however they're perfectly valid string characters and
the standard library's marshaller does not check for them, embedding
them directly in the output document and breaking the client's
decoding.
Work around the issue by replacing such binary data with an empty
string.
While at it, move the bytes shim to the customized marshaller, this
way everything's at the same place and it's not necessary to waste
time trying to understand why the marshaller is just not calling what
it's supposed to call.
Fixes#61919closesodoo/odoo#75973
Forward-port-of: #75952
Forward-port-of: #74699
X-original-commit: 1a0b3f7
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
PR #42723 changed the public method context_get on res.users return a
frozendict instead of a classic CPython dict.
Since the default XMLRPC Marshaller does not know how to serialize a
frozendict, this would result in errors when calling the method directly
via the XMLRPC layer.
This commit solves this issue by defining a marshalling procedure for
frozendict objects in our custom OdooMarshaller class, this simply
converts the frozendict into a dict and uses the default dict-to-xml
dump procedure (dump_struct).
Fixes#75412closesodoo/odoo#75478
X-original-commit: e80a299ed910cacac4aa4e64164909af36ce62ad
Signed-off-by: Adrian Torres (adt) <adt@odoo.com>
odoo/odoo#74678 fixed the universal traceback which would happen any
time an HTML field would be read, however it's incomplete because:
* it was tested on a field which wasn't HTML in 14.4
* and no markup was put in the field anyway
So the markup being embedded in the XML-RPC document unescaped was
missed, leading to:
* corrupted (partial) responses when the HTML content is XML-valid,
depending on the exact API of the client it might only return the
first or last text segment, or all the text without markup, or
something else
* outright deserialisation error on XML-invalid content (e.g. void
elements like <br>)
The cause being that `Markup` overrides all `str` methods to first
escape their parameters before actually applying on the object. This
means `xmlrpc.client.escape` would basically do nothing, then would
concatenate the `Markup` into the document (stringifying it) and send
the entire thing on its way.
Fixes#74884closesodoo/odoo#74957
X-original-commit: 8a0f7d820cb2296f410be215ffeadd1cefae174c
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
In 01875541b1, HTML fields (and various
methods) were made to return markupsafe.Markup objects.
However at the time I didn't consider that XML-RPC serialization
remains based on type *identity*, and thus the `Markup` object would
not serialize outbound through XML-RPC, and would blow up instead.
This should fix the issue, by serializing Markup objects as str.
closesodoo/odoo#74684
X-original-commit: 165bd3bf88becc42416e49ad2f430e90675219fa
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
We provide a new helper class to help redact x2many commands for create
and write methods. To ensure best compatibility with the xmlrpc layer we
do not change the protocole, the commands are still 3-elements tuples
where the first element is still an integer in between 0 and 6. The
helper class provide the cannonical constants and static methods to ease
working with the commands. The new helper class is also available in QWeb.
Developers are encouraged to transition their code so it uses this new
helper class.
Task: 2366606
Also non-browser jsonrpc (as it goes through a similar process): for
internal performance reasons, name_search and read_group have been
converted to a *lazy* name_get, so the "display name" is not
unnecessarily computed.
However this is an issue for the RPC endpoints (/xmlrpc and /jsonrpc)
as they have no support for `lazy` and thus tend to blow up and / or
do the wrong thing when trying to output a lazy:
* xmlrpc has no way to handle lazy at all and straight blows up
* jsonrpc falls back to `json_default` so they try to stringify the
lazy, which might have worked except
*Problematically* both endpoints delegate the actual work to
`dispatch_rpc` which handles dispatching between various services and
ultimately creates a *new* cursor before calling model
methods (`object` service and `execute`/`execute_kw`).
This means by the time the result is serialized to be output, the
lazy's cursor has long been closed, and thus any access to an
unevaluated `lazy` errors out when trying to fetch the underlying
item.
This also means we can't just add a hook to serialize the lazy
in the xmlrpc marshaller, though we do have to do that. We *also* (for
both xmlrpc and jsonrpc) have to force evluation of lazy values before
our cursor is closed, meaning it has to be done right after the method
is invoked, iterating the entire response.
Related to task 2170343
closesodoo/odoo#49286
X-original-commit: e2b5a359c1d5eccbe725c1c3169b4130d7bca49b
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
`method` has no effect, so currently XML-RPC can be called via other
methods, e.g. GET, which is against XML-RPC specification.
closesodoo/odoo#37917
X-original-commit: c2fe13d31f6b55900ad139d4e75b8c1a0c4ac165
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
Before this revision, trying to read a Date field using xmlrpc would
result in a marshalling error.
This is due to the fact that 960360afe4
changed the internal value of Date/Datetime fields to hold
datetime.date/datetime objects.
The xmlrpc layer is capable of converting datetimes to the XML
datetime representation, but this is not possible for datetime.date
objects.
In order to solve this, the Marshaller class used by python's
xmlrpc.client is overridden and monkey-patched, allowing to convert
datetime.date / datetime.datetime objects into properly formatted
strings.
opw-1896364
closesodoo/odoo#28022
Endpoints can be explicitly marked as `save_session=False` (default is
true across the board). In that case they will have an in-memory session
(either the existing one or a brand new one) but the session won't be
persisted to disk.
Currently used for non-browser RPC endpoints: the APIs don't use
cookies/sessions and we can't assume the RPC libraries keep cookies
across calls. This means a new session is created and saved to disk for
each RPC calls, for no useful reason.
This way, XMLRPC calls can get request details form the standard
`odoo.http.request` system.
Move jsonrpc to the same controller while at it, for coherence.
Fix#24183