png images not shown on ir.attachment kanban
Attachment that use db_datas have no checksum by default, which is used
to compute the stream's http ETag. Skip updating the ETag when it is
missing and determine freshness using the Last-Modified header instead.
closesodoo/odoo#139498
X-original-commit: 2d43bbae72fddf17e7d9045e90dbc070b2f57a19
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
The limit was only enforced by the front-end, meaning that anybody could
forge a request with a huge file and get it processed by Odoo. According
to the documentation of werkzeug[^1], such limit should be enforced by
the server server instead of the wsgi application. It is the case for
Odoo Online but on-premise customers might not configure their servers.
The `web.max_file_upload_size` system paramter is now enforced upon
parsing the content of the request. It defaults at 128 MiB which is
enough for most documents and images. We do not want to host large
files (e.g. videos) in the Odoo filestore.
[^1]: https://werkzeug.palletsprojects.com/en/2.0.x/request_data/Fixes: #124646
Part-of: odoo/odoo#126914
Let's assume that
* Company S is a sub company of it's parent company P
* Company S has access to all the accounts and taxes of company P
* Some taxes are archived, but used
Because of the needed access rules, there will be a `parent_of` on the
record rules of accounts and taxes.
If we consider that we should consider the context key `active_test` to
add a implicit `('active', '=', True)` clause in the domain when
evaluating `parent_of` and `child_of` clauses, an access error will be
raised instead of hiding the archived records, even when simply trying
to read an archived record.
The archive feature and the security rules should be independent; if a
security rules needs to depend on the fact that a record is archived, it
should be explicit in the domain and not rely on side effects of the
implementation of `parent_of`/`child_of`
Part-of: odoo/odoo#125642
Web lacked a default route for /robots.txt meaning that if you didn't
installed website (which comes with a full fledged robots.txt) you would
get a 404 page not found.
closesodoo/odoo#127402
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
Send a request to any json-rpc route with a HTTP header
`Content-Type: application/json-rpc` but send non-json or
non-jsonrpc data in the body. The application crashes with
a 500 Internal Server Error instead of a 400 Bad Request one
closes odoo/odoo#124571
Closes: #122048
X-original-commit: a1b83b07996f3fe4744474ff4023a3a2ce17ac7f
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
Before this revision, when you pass `context` in the arguments
of a JSON routes, this one gets automatically injected
in the environment context.
This is not the case for regular HTTP routes.
It makes sense to propagate the context for the JSONRPC protocol,
JSON routes used by the backend, such as `call_kw`,
but it doesn't make sense to pass this context automatically
for any other kind of routes, such as front-end routes
or routes used by custom Javascript widgets.
This change brings a more unified behavior for routes
of types HTTP and JSON.
In addition, most developers were not aware of this "feautre",
that passing `context` in the arguments of a JSON route leaded
to the injection of this context in the environment context.
This is actually reflected by the diff size this changes required,
only a dozens of routes needed to be adapted, to manually
add the context in their route arguments and to inject it
in their environment context.
closesodoo/odoo#121726
X-original-commit: a7a5655631e6d5b05fd2ba3d0c80617aae6d9cfe
Related: odoo/enterprise#41229
Signed-off-by: Denis Ledoux (dle) <dle@odoo.com>
Before this commit:
When uploading a file, if the transaction fails due to a serialization
failure, Odoo will retry the request. However, if a file upload is read
during the transaction, the file pointer will be at the end of the file,
and calling `.read()` again returns an empty bytes object.
After this commit:
Upon retrying the request, rewind uploads to the beginning of the file,
if the file supports it.
opw-3228200
closesodoo/odoo#120180
X-original-commit: ac59ef0668122ad71dffbb5575250c767a0a56ec
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
A visitor could visit a web page having a lang in its context that is
not installed in the databased he is connected to. The problem is that
visitors are not logged-in thus it is not possible to determine their
lang via their `res.users` preferences. The lang used instead is the
lang set in the `Accept-Language` header of the incoming request, that
header is set by various browsers in accordance to the user system
preferences or browser settings.
The browser lang (`Request.best`) is only parsed according to the
`babel` database, it is a lang syntactically speaking but not necessary
a lang that is installed in the database.
At the moment the browser lang is set in the context (inside of
`Request._get_dbname_and_session`), it is not possible to verify it is
installed in the database as no connection to any database as been
established yet. Instead the lang is validated inside of
`ir.http._pre_dispatch` which is the method responsible to prepare/fix
various stuff on the request/session/context.
In regard to 93b684d3c7, we prefer to fallback on English, hence the
modification in `get_lang`.
closesodoo/odoo#116683
Reference-to: 93b684d3c7 ([FIX] base: lang should fallback on english instead of arab)
X-original-commit: 743e97667e44cdaab6db334d807cf3d409cea621
Signed-off-by: Julien Castiaux (juc) <juc@odoo.com>
With the special support for postmortem debugging removed, the
likelihood of needing / wanting the werkzeug remote debugger seems
even more remote (as it works in strictly less situations, only for
frontend non-json requests).
So remove that as well.
closesodoo/odoo#115176
X-original-commit: a2022783b652299155c460294c00dbced9b619ac
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
Start odoo-bin shell with `--geoip_country_db='/i/dont/exist'` and type
the following code:
from odoo.http import GeoIP
GeoIP('8.8.8.8').country_code
TypeError: The country method cannot be used with the GeoLite2-City
database
There are two "things" here: the raw country and city entries in the
databases and the rich python country and city objects returned when an
entry was found and parsed.
Then there are two "readers", a reader capable of reading and parsing
entries from the city database and **another** reader for the country.
The two readers are **only** compatible with their specific database:
the city reader cannot read or parse information from the country
database and vis-versa. That's the bug reported by the TypeError that
this commit fixes.
But, the two python instances created from parsing the entries of
respecting databases with respecting parsers **do** share a same API:
the city record class inherits from the country record class.
# Valid
city_db = geoip2.database.Reader(config['geoip_city_db'])
city_record = city_db.city('8.8.8.8')
city_record.country.name # works, a city record also
# holds country attributes
# Invalid
city_db = geoip2.database.Reader(config['geoip_city_db'])
country_record = city_db.country('8.8.8.8') # TypeError
closesodoo/odoo#109095
Signed-off-by: Julien Castiaux <juc@odoo.com>
Maxmind offers multiple ip-geolocalization databases, historically we
have been using the City database which contains records on a
city-basis. Many years later it turns out we are primary using geoip to
know the country of the user. Geolocalization in the City database is
considered slow by our standard and we have been clever in order not to
geolocate each request by saving the info in the session.
On the other hand, the Country database that is offered by Maxmind is
much more lightweight and geoip using that country is considered a fast
operation by our standard.
In this work we make Odoo compatible with both the City and the Country
databases. Using multiple database at the same time, we can be smart and
only query each of the two on-demand. If a user ask for its country,
we'll use the fast Country db. If a user ask for its city/timezone we'll
use the slower City db.
By default it loads both database from the `/usr/share/GeoIP/` folder,
respectively the files `GeoLite2-City.mmdb` and `GeoLite2-Country.mmdb`,
you can provide alternative paths using the `--geoip-city-db` and
`--geoip-country-db` CLI options.
In the same mindset as #86015, geoip is still lazy. It is done on-demand
and the result is cached on the current request. The different with the
related PR is that as we know consider geoip to be fast, we no longer
cache the result in the session.
Task: 2848206
Part-of: odoo/odoo#91337
*: base_setup, hr_timesheet, mail, partner_autocomplete, web_tour
Start odoo without -d and with a --dbfilter that allows multiple
databases. Via JSON-RPC access the /web/session/authenticate route
providing a non-filtered database and valid credentials. Traceback,
`request.env` is None.
Since httpocalypse the initialization of the ORM (cursor, registry,
environment) is greedy. It means that the connection to the database is
established very early during the request routing or skip altogether in
case no dbname was known at that time. This contrast with prepocalypse
where the various ORM thingies were lazily setup the first time they
were accessed.
This changement has an important implication regarding authentication.
In prepocalypse, thanks to the lazy approache, a cursor/registry/env
would be setup on the database you just login upon using the
`request.env` for the first time. This was very nice in this regard but
had other problems.
Since httpocalypse such operation is no more possible. Devs must
initialize and use their own cursor/registry/env in case they
authenticate on another database than the one `request.cr` is (maybe)
connected to.
The `/web/session/authenticate` controller is an example of such case.
It crates its own cr/registry/environment after authentication. The
problem the controller uses `ir.http.session_info` and that not all
overrides were updated to use `self.env` (=the env created in the web
controller) instead of `request.env` (=the missing env of the request).
closesodoo/odoo#108063
X-original-commit: 7b9bd9d37731fae724dc5d91da656dab70aa9ad4
Related: odoo/enterprise#35012
Signed-off-by: Julien Castiaux <juc@odoo.com>
Define the following controller:
@route('/get-context', auth='public', type='json', website=True):
return request.env.context
Access that route via JSON-RPC providing a context:
this._rpc({
route: '/get-context',
params: {
context: {"a": 1}
}
})
Since httpocalypse, it replaces the context entirely instead of updating
it. i.e. before you would get along those lines:
{"a": 1, "lang": "en_US", "tz": "Europe/Brussels", "uid": 2}
but since you get instead (and that's wrong):
{"a": 1}
Note that after this commit, this merging-context behavior will be the
same whether or not website=True is defined (while it was only there for
website=True before).
Discovered via opw-2885948
X-original-commit: 7887cfc3f177d9e64f008aabb8bd710f54024dea
Part-of: odoo/odoo#107179
Move code to support only the redirect from url containing double '/' in
the middle of the path.
Keep same behavior than v15 and default Apache behavior.
domain.com//shop/product/1 -> 404
domain.com/shop//product/1 -> 301 -> /shop/product/1
opw-3063387
closesodoo/odoo#106137
X-original-commit: fdd6bf9942e2807b6d1460dba1ca5f61404c7b06
Signed-off-by: Julien Castiaux <juc@odoo.com>
Signed-off-by: Jérémy Kersten <jke@odoo.com>
Create a 15.0 database with website, access the home page via your
browser. Stop the server and migrate the database to 16.0. Restart the
server with a `--dbfilter` that rejects the database you created and
refresh your browser. 500 Internal server error, attribute error:
the `request` object as no `session`.
An error could occurs after a migration to 16.0 due to the presence of
the `geoip` key in the session. `request.session.geoip` has been made a
deprecated alias to `request.geoip` between 15.0 and 16.0, see 04e9726.
Because the session was created before 16.0, the session dict does
contain a `geoip` key. Upon logging the session out, the session dict
is cleared. The default implementation of `clear()`[^1] inside of
`collections.abc.MutableMapping` can be summarized for our usecase to:
for key in self:
value = self[key]
del self[key]
There is an extra `__getitem__` call due to `value = self[key]`, in the
case of the `geoip` key, it would access the alias. It is not possible
to accessing that alias inside of the `_get_dbname_and_session` method
of request as the session has not been set on `self` (the request) yet.
Yet inside of that method, we do `session.logout()` which `clear()` the
session which (wrongly) access the alias because `geoip` exists in the
internal dict (`'geoip' in self.keys() # True`).
The solution has been to implement the `clear()` function ourself
instead of using the mixin of `MutableMapping`.
[^1]: https://github.com/python/cpython/blob/b43496c01a554cf41ae654a0379efae18609ad39/Lib/_collections_abc.py#L925-L931closesodoo/odoo#105763
X-original-commit: b66e1ffa8e348eedf2de735babbc398290a8bffb
Signed-off-by: Julien Castiaux <juc@odoo.com>
This fix allows generating the sitemap (via `website.search_pages`) via
RPC. The changes are necessary as since #99667 the `request` object is
no more available to RPC-executed functions.
See also: the `test_search` test case of `website.tests.test_page`.
closesodoo/odoo#104567
X-original-commit: 8f4e214417cfb1aed7e595b8d6ab71f33a347b29
Signed-off-by: Julien Castiaux <juc@odoo.com>
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
When a file is immutable the different network layers can cache it.
Services receiving this header should never invalidate these files.
Part-of: odoo/odoo#95500
Emails got always the odoo logo even if the company logo has been changed. This
solves the problem.
Technical note: the problem was caused by an exception in the controller due to
invalid parameters used for send_file method causing web/static/img/nologo.png
to be returned.
Task-2920690
closesodoo/odoo#99073
Signed-off-by: Julien Castiaux <juc@odoo.com>
Not entirely sure about TestAllocationRights. For TestEsEdiCommon
issue is quite obviously that it's inherited by tests which are
external, so when the `post_install_l10n` tag gets applied those tests
get run during "normal" l10n and they break.
closesodoo/odoo#98814
Related: odoo/enterprise#30825
Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
Prior to saas-15.4, access /web/content/res.users/4/image_128 without
being logged in, there was an internal server error because you cannot
access the public user (id=4) image.
The saas-15.4 branch is unaffected by the bug but it is a good idea to
forward-port the test that was next to the fix merged in prior versions.
Closes#94258closesodoo/odoo#98201
X-original-commit: 4deb7e373e046844d997ddc0a11999cc12b765d8
Signed-off-by: Julien Castiaux <juc@odoo.com>
Co-authored-by: ypn <ypnwebdev@gmail.com>
An HTTP Partial Request is a regular GET request with a Range header
that indicate what chunk of the data the browser wishes to download. It
is useful to peek in a video stream or to resume an interrupted
download. The server can respond with a 206 - Partial Content response,
set the appropriate Content-Length and Content-Range headers and only
send a chunk of the data in the body.
Werkzeug's `send_file`, the library function we use to stream files over
http, is fully compliant with partial requests and responses. It
understands the Range request header and create the corresponding
response.
NGINX does also comply with the Range header even via X-Accel-Redirect.
closesodoo/odoo#97422
Signed-off-by: Julien Castiaux <juc@odoo.com>
This commit aims at removing unuseful help message to:
1/ reduce translators work, to focus on more useful translations
2/ not sending unuseful information in load_views
3/ reduce help message to useful messages, so that we can mark
fields having a tooltip in the future UI.
4/ some cleanup of existing messages too
The main use cases:
- REMOVED: help redundant with the field name, providing no extra info
- MOVED TO COMMENT: technical help messages, that should not be in UX
closesodoo/odoo#97279
Signed-off-by: Fabien Pinckaers <fp@odoo.com>
Create an empty image attachment and load it via an `<img>` html tag in
a document. Upon rendering the image is replaced by the default browser
placeholder instead of the pretty Odoo one.
closesodoo/odoo#95702
Task: 2886028
X-original-commit: 981d56f131f85d33e2415edaef36cfa501d86f0e
Signed-off-by: Julien Castiaux <juc@odoo.com>
It allows to always have a OdooResponse Object and don't allow redirect
to external except when you allow it explicitly with local=False.
Always return to a local url:
/website/add
/slides/slide/<model("slide.slide"):slide>
/microsoft_outlook/confirm
Allow previously external redirect without reason, now blocked
/website/lang/<lang> -> open redirect
Allow external redirect for good reason and url is controlled by code.
/social_facebook/redirect_to_profile/
PS: HTTP Code 303 is a better default for generic redirects. It's not
historically the default for werkzeug.utils, but it is what we want in
general. Contrary to 302, there is no browser-dependent behavior, and
no risk of asking the user whether they want to accept the redirect if
the original method wasn't GET. It's always a non-permanent GET on the
target location.
closesodoo/odoo#95019
X-original-commit: 77f8d9c5d96a9274785ffc2ad83b95ea157d26ad
Related: odoo/enterprise#29000
Signed-off-by: Olivier Dony <odo@odoo.com>
Signed-off-by: Jérémy Kersten <jke@odoo.com>
Rationnals
----------
Web servers can serve some resources (e.g. static files) right away
without any interaction with the web application. The network model of
most web servers makes them capable of handling thousands of
simultaneous requests when it comes to intensive IO operations such as
streaming data from a file. The network model of Odoo is different: it
is capable of a lot of processing power but can only serve a handful of
requests at a time, i.e. Odoo (with some help from postgres) is
optimized for CPU operations, not IO.
Some users don't configure their web server, they use a basic
configuration that relay all requests to Odoo. The result is that many
Odoo HTTP Workers can be busy streaming static files instead of
processing other requests. This can lead to a worker starvation, i.e.
all workers are busy streaming files and cannot process new requests.
X-Sendfile
----------
In this work, we add the support for the [X-Sendfile] header family,
they are multiples http headers that can be used by the web application
to communicate with the web server in order to delegate the delivery of
files stored on the file system. Odoo still receives the request but it
does no more stream the file content from within its HTTP worker,
instead it skips the response body altogether and sets the `X-Sendfile`
special header with the path of the file on the filesystem. The web
server intercepts that special header, open the file and stream it.
Using those headers, we can use the best of both the web application and
the web server. The web application is still responsible to locate the
resource and verify the access rights, the web server is still
responsible of streaming the content.
Using X-Sendfile is opt-in via the `--x-sendfile` CLI flag. We set both
`X-Sendfile` (apache) and `X-Accel-Redirect` (nginx). If you are using
apache, make sure `mod_xsendfile` is enabled. If you are using NGINX
you have to add the following location block:
location /web/filestore { # custom path, hardcoded within Odoo
# Prevent access from the outside world, i.e. makes this
# route only accessible via X-Accel. MANDATORY!!!
internal;
# Give access to the filestore using this server's
# permissions. Odoo is in charge of verifying the access
# rights.
alias /path/to/odoo/data-dir/filestore;
}
The Odoo [deployment documentation] has been updated accordingly.
[X-Sendfile]: https://www.nginx.com/resources/wiki/start/topics/examples/xsendfile/
[deployment documentation]: https://www.odoo.com/documentation/master/administration/install/deploy.html#serving-static-files-and-attachments
Changes to the API
------------------
To benefit most from X-Sendfile, all APIs related to streaming content
over HTTP has to be adapted. They are: (1) `request._serve_static`,
(2) `ir.http._serve_fallback`, (3) `/web/content` and (4) `/web/image`.
Each used it own way to deliver content: (1) `_serve_static` was using
`send_file` (flask's send_file that as been vendored with odoo 10
years ago and not maintenained since then), (2) _serve_fallback was
handcrafting a `werkzeug.wrappers.Response`, (3) /web/content-image were
using the "binary server" `ir.http.binary_content` API.
I has been decided to remove all 3 APIs and to merge the code inside of
the new `http.Stream` object and the `ir.binary` helper model.
A Stream wraps what is going to be sent to the browser, it can be a path
to a file on the locale filesystem, a blob of raw data or an URL to an
external resource. The Stream also holds various metadata that are
mainly used for caching. The preferred way to create a Stream is via one
of its three factories so that all the metadata are set. The factories
are: `from_path`, `from_attachment` and `from_binary_field`. A stream
instance exposes a single method `get_response()` used to create the
corresponding HTTP response object out of the stream.
Inside of `ir.http` were a few methods that were not related to the http
routing and formed what was called the "binary server". All those
methods have been removed and the feature have been refactored inside of
the new `ir.binary` model. The removed methods are:
- `_xmlid_to_obj`
- `_get_record_and_check`
- `_binary_ir_attachment_redirect_content`
- `_binary_record_content`
- `_binary_set_headers`
- `binary_content`
- `_response_by_status`
- `_get_content_common`
- `_content_image`
- `_content_image_get_response`
- `_placeholder_image_get_response`
The new `ir.binary` abstract model exposes the following utilities:
**`_find_record`**
Find an attachment or a record with a binary-field out of an xmlid or
out of a pair record-model/record-id. Check the access rights and the
access token.
**`_get_stream_from`**
Create a Stream from an attachment or a record with a binary-field.
**`_get_image_stream_from`**
Same as `_get_stream_from` but adapted for images. It sets a sensible
ETag on the stream and has image resizing support.
**`_placeholder`**
Get the image placeholder blob.
Testing
-------
It is possible to test the web server configuration using the
`test_http` module. Install the module then run the unittest using the
`webserver` test-tag. By default it attempts to connect to a web-server
running on `http://localhost:80`, you can change this URL by setting the
`WEB_SERVER_URL` environment variable.
odoo-bin -i test_http --stop-after-init
WEB_SERVER_URL='http://localhost:80' odoo-bin --test-tags webserver --stop-after-init
closesodoo/odoo#88134
Task: 2801675
Related: odoo/documentation#2083
Related: odoo/enterprise#26191
Signed-off-by: Julien Castiaux <juc@odoo.com>
We introduce a new decorator/context-manager to catch some exceptions
and re-raise them as another error. This utility main's purpose is to
hide a route that a user has no access to behind a fake HTTP 404 Page
not Found error.
The utility is at `odoo.tools.misc.replace_exceptions(*exceptions, by)`.
Its usage is as follow:
@route('/some/route', auth='public')
@replace_exceptions(AccessError, AccessDenied, by=NotFound())
def some_route(self):
if not request.session.uid:
raise AccessError("Must be connected to see this route")
...
Or as a context-manager if you don't want to except an entire function:
@route('/some/route', auth='public')
def some_route(self):
with replace_exceptions(AccessError, AccessDenied, by=NotFound()):
if not request.session.uid:
raise AccessError("Must be connected to see this route")
...
Task: 2800772
Close: #90433
Part-of: odoo/odoo#88134
When started with the CLI option --dev=werkzeug, errors in controllers
are caught by a friendly web debugger. This debugger should not be
started in case of error in a JSON-RPC controller.
closesodoo/odoo#90420
Task: 2837457
X-original-commit: 711a29e76f55e87d73dad89ddbef889dd5c7af10
Signed-off-by: Julien Castiaux <juc@odoo.com>
Remove most values uselessly specified because giving the same value as
the default one (see _DEFAULT_MANIFEST in odoo/modules/module.py)
* auto_install is Falsy by default
* author is Odoo SA by default
* summary & description are empty strings by default
* application is False by default
* test, demo, depends and data are empty lists by default
This will reduce noise/inconsistencies between manifests specifications,
simplify analysis of manifests content, ...
closesodoo/odoo#90209
Related: odoo/enterprise#26807
Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
With this work we relax the http controller so that it accepts all
requests, including `Content-Type: application/json`. We also enrich
the framework with two new helper methods dedicated to serialaze json
requests and responses:
- `request.get_json_body()`, loads the json content from the request's
body and returns the corresponding python object (usually a dict).
- `request.make_json_response(data)`, dumps `data` to json and makes an
http response out of it.
closesodoo/odoo#86300
Task: 2779837
Signed-off-by: Julien Castiaux <juc@odoo.com>
Every request comes with a session, a dictionary that is persisted on
the filesystem and that saves various information such as the user
cart on the ecommerce.
When a user simply visits the website, a default session is created and
saved on disk, this bloats the filestore with many sessions. Creating
the session on-the-fly is cheaper than loading it from the filesystem.
With this work the default session is not saved on disk anymore unless
explicitly asked via `session.touch()`.
An exception to the statement "creating the session on-the-fly is
cheaper" is geoip, the ip geolocalization is not cheap. In this work,
geoip have been moved from http_routing/request.session.geoip to a
lazy property core/request.geoip. When requested the info is persisted
on the session. Like other keys from the default session, geoip will not
be persisted unless there is non-default stuff in the session.
Because the CSRF-TOKEN is based on the session-id, it is important the
session-id stays the same across multiples requests even when the
session is not persisted on disk. Even when a session is not persisted
on disk, the session-id cookie is still set so that the next session
created on-the-fly uses the same session-id.
Technical note regarding the session, it has been decided to drop the
session-snapshot protocol and to reintroduce a "modified" flag. It has
been decided not to use werkzeug's session (which natively comes with a
"modified" flag) and to keep our own session object. We decided to
extend MutableMapping instead of dict; using MutableMapping we only
have to override __setitem__ and __detitem__; using dict we would had to
override update()/pop()/... too.
Task: 2789035
Part-of: odoo/odoo#86015
The odoo.addons.web.controllers.main python module have been splitted
over multiple files on the basis 1 controller = 1 file. In this work we
adapt all modules to use the new imports.
A non-exhaustive list of where stuff have been moved:
* main.Home --> home.Home
* main.Session --> session.Session
* main.WebClient --> webclient.WebClient
* main.clean_action --> action.clean_action
* main.ensure_db --> home.ensure_db
The complete list is accessible in odoo.addons.web.controllers.main.
closesodoo/odoo#87571
Related: odoo/enterprise#25746
Signed-off-by: Raphael Collet <rco@odoo.com>
Install website, create a custom web page, we'll call it page_1. Ensure
you are not in debug mode (go to /web/health?debug=0 to disable it).
Open the web page enabling the debug-mode /page_1?debug=1, the page
opens but the debug mode is disabled.
Because web pages are served using another routing mechanism than
controlers we have to ensure we load the debug query-string in those
mechanisms too.
closesodoo/odoo#85340
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
This commit is the 15th commit of a comprehensive refactor of our HTTP
framework. See odoo/odoo#78857 for complete historic, discussions and
rationnals.
Enhance the new test_http module with more tests.
Pr: odoo#78857
Task: 2571224
Related: odoo/enterprise#21849
Related: odoo/design-themes#524
Signed-off-by: Julien Castiaux <juc@odoo.com>
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
Backport from the master-httpocalypse-juc test suite in order to observe
the perf of the master branch and to compare them with the httpocalypse.
closesodoo/odoo#84156
Task: 2571224
Signed-off-by: Raphael Collet <rco@odoo.com>