Repository: CS-SI/eodag

Issue:
staging status in server mode download 
When downloading an OFFLINE product in server mode, use min values for `wait` and `time` and return a 202 status until product is available

Discussion:
github-actions[bot]: ## Test Results
    3 files  +    1      3 suites  +1   3m 12s [:stopwatch:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v2.11.0/README.md#the-symbols "duration of all tests") + 1m 9s
431 tests +    1  427 [:heavy_check_mark:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v2.11.0/README.md#the-symbols "passed tests") +    1  3 [:zzz:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v2.11.0/README.md#the-symbols "skipped / disabled tests") ±0  1 [:x:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v2.11.0/README.md#the-symbols "failed tests") ±0 
973 runs  +422  966 [:heavy_check_mark:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v2.11.0/README.md#the-symbols "passed tests") +419  6 [:zzz:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v2.11.0/README.md#the-symbols "skipped / disabled tests") +3  1 [:x:](https://github.com/EnricoMi/publish-unit-test-result-action/blob/v2.11.0/README.md#the-symbols "failed tests") ±0 

For more details on these failures, see [this check](https://github.com/CS-SI/eodag/runs/18626106596).

Results for commit f9c1e23e. ± Comparison against base commit f323366a.

[test-results]:data:application/gzip;base64,H4sIAGYqUmUC/02MQQ6DIBAAv2I496BsBbefaSwsCalKg3Bq+vcuVanHmUnmLZyfaBW3Bi6NWLNPFWyOY/JhYexQsuCUSrxCd9B9zcYUJfVfPf1rX2zCjX4qkyooxhDZtGxiXsoTNexwLFGparZj5dPwx+efCfPsE4NwaDqSQA/UGqmXowE59IQWsCVwViFrpwbx+QKE/s9sBQEAAA==

github-actions[bot]: <strong>Code Coverage (Ubuntu)</strong>

| File | Coverage |   |
| - | :-: | :-: |
| **All files** | `82%` | :white_check_mark: |

_Minimum allowed coverage is `70%`_

<p align="right">Generated by :monkey: cobertura-action against f9c1e23eb9779e52ac3285e9d390e3fd6979ef68 </p>
github-actions[bot]: <strong>Code Coverage (Windows)</strong>

| File | Coverage |   |
| - | :-: | :-: |
| **All files** | `53%` | :x: |

_Minimum allowed coverage is `70%`_

<p align="right">Generated by :monkey: cobertura-action against f9c1e23eb9779e52ac3285e9d390e3fd6979ef68 </p>
github-actions[bot]: ![badge](https://raw.githubusercontent.com/CS-SI/eodag/_xml_coverage_reports/data/871-staging-status-in-server-mode-download/./badge.svg)


## Code Coverage (Ubuntu)

<details>


```
Filename                                     Stmts    Miss  Cover    Missing
-----------------------------------------  -------  ------  -------  ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
__init__.py                                     11       0  100.00%
cli.py                                         300      47  84.33%   61, 647-686, 788-839, 843
config.py                                      318      27  91.51%   80-82, 91, 99, 103-105, 178, 190, 391-393, 457-460, 507-508, 517-518, 597, 666-671, 673
crunch.py                                        6       6  0.00%    18-24
api/__init__.py                                  1       0  100.00%
api/core.py                                    727      76  89.55%   87-96, 369, 582, 626-629, 667, 772, 776-781, 807, 877, 954, 1068-1073, 1159-1171, 1211, 1213, 1217, 1238-1240, 1244-1255, 1268-1274, 1364-1367, 1396-1416, 1464, 1470-1473, 1482, 1848, 1881-1887, 2152, 2156-2159, 2173-2175, 2210
api/search_result.py                            44       6  86.36%   33-35, 70, 79, 86, 100
api/product/__init__.py                          6       0  100.00%
api/product/_assets.py                          44       5  88.64%   27-29, 79, 129
api/product/_product.py                        211      32  84.83%   53-60, 64-66, 170-177, 261-262, 352, 388, 449, 463-466, 479, 503-506, 549-555
api/product/metadata_mapping.py                649      82  87.37%   67-69, 130-132, 233, 265-266, 318-330, 332, 343, 349-361, 402-405, 442, 463-466, 489, 497-498, 571-572, 596-597, 603-606, 621-622, 771, 817, 934-939, 1070, 1084-1104, 1124, 1129, 1239, 1261, 1275, 1288-1307, 1346, 1398, 1436-1440, 1459
api/product/drivers/__init__.py                  6       0  100.00%
api/product/drivers/base.py                      8       2  75.00%   23, 41
plugins/__init__.py                              1       0  100.00%
plugins/base.py                                 23       3  86.96%   25, 48, 55
plugins/manager.py                             127      14  88.98%   49-51, 95-100, 146, 185, 205, 231, 270-271
plugins/apis/__init__.py                         1       0  100.00%
plugins/apis/base.py                             4       0  100.00%
plugins/apis/ecmwf.py                           99      15  84.85%   47-55, 156-158, 205-206, 232-234
plugins/apis/usgs.py                           172      36  79.07%   59-64, 128, 201, 235, 270-272, 277, 303-304, 309, 339-346, 357-362, 384-390, 392-398, 421
plugins/authentication/__init__.py               7       1  85.71%   31
plugins/authentication/aws_auth.py              20       2  90.00%   25-27
plugins/authentication/base.py                  19       3  84.21%   26, 34, 47
plugins/authentication/generic.py               16       3  81.25%   28, 40, 50
plugins/authentication/header.py                17       1  94.12%   27
plugins/authentication/keycloak.py              88      17  80.68%   32-34, 159-160, 190-212, 238-243
plugins/authentication/oauth.py                 15       8  46.67%   25, 32-34, 38-41
plugins/authentication/openid_connect.py       103      64  37.86%   39-41, 138-150, 154-172, 180-222, 228-237, 246-286, 291-299, 304-305
plugins/authentication/qsauth.py                36       2  94.44%   32, 83
plugins/authentication/sas_auth.py              49       2  95.92%   32, 76
plugins/authentication/token.py                 81      13  83.95%   35-37, 86, 99, 101, 114-117, 165-168
plugins/crunch/__init__.py                       1       0  100.00%
plugins/crunch/base.py                          10       2  80.00%   25, 38
plugins/crunch/filter_date.py                   62      15  75.81%   30, 53-58, 72, 81, 90, 93, 105-107, 116-118, 125
plugins/crunch/filter_latest_intersect.py       50      10  80.00%   32-34, 51-52, 71, 80-83, 85, 92-95
plugins/crunch/filter_latest_tpl_name.py        33       2  93.94%   28, 86
plugins/crunch/filter_overlap.py                68      17  75.00%   28-30, 33, 82-85, 91, 99, 110-126
plugins/crunch/filter_property.py               33       8  75.76%   29, 60-65, 68-69, 85-89
plugins/download/__init__.py                     1       0  100.00%
plugins/download/aws.py                        491     165  66.40%   77-83, 272, 285, 352-355, 369-373, 419-421, 425, 458-459, 465-469, 502, 537, 541, 548, 578-586, 590, 628-636, 643-645, 686-760, 778-839, 850-855, 871-884, 913, 928-930, 933, 943-951, 959-972, 982-1001, 1008-1020, 1061, 1087, 1132-1134, 1354
plugins/download/base.py                       261      57  78.16%   58-64, 145, 180, 319-320, 340-346, 377-381, 387-388, 432, 435-449, 461, 465, 538-542, 572-573, 581-598, 605-613, 615-619, 666, 689, 711, 719
plugins/download/creodias_s3.py                 17       9  47.06%   44-58
plugins/download/http.py                       458      94  79.48%   82-88, 122, 196-208, 211, 292-297, 321, 323, 387, 414-416, 426, 432, 434, 458, 497-501, 558, 644-700, 718, 751-760, 786-787, 814, 838, 846-851, 873-874, 881, 942-948, 1003-1004, 1010, 1020, 1086, 1090, 1104-1120
plugins/download/s3rest.py                     117      27  76.92%   55-58, 124, 165, 199, 229-236, 239-241, 245, 258-264, 272-273, 276-280, 303, 324-327
plugins/search/__init__.py                       1       0  100.00%
plugins/search/base.py                         127       9  92.91%   49-54, 108, 112, 275, 295, 378
plugins/search/build_search_result.py          179      22  87.71%   62, 97, 142-143, 149, 160, 290-293, 327, 384-396, 458, 461, 471, 488, 516, 518
plugins/search/creodias_s3.py                   54       3  94.44%   55, 73, 107
plugins/search/csw.py                          107      83  22.43%   43-45, 57-58, 62-63, 74-122, 128-141, 149-181, 199-240
plugins/search/data_request_search.py          198      65  67.17%   52, 89-92, 108, 120, 124-125, 139, 144, 149, 156, 169-172, 226-227, 231, 241-247, 252, 280-283, 291-302, 319, 321, 328-329, 331-332, 350-354, 387, 394, 405, 418, 424-436, 441
plugins/search/qssearch.py                     561      65  88.41%   89, 361-367, 375-376, 483-489, 544-547, 620-621, 662, 680, 695, 748, 769, 772-773, 782, 793, 802, 825, 885-890, 894-895, 923, 994, 1013-1030, 1069, 1145-1149, 1215-1216, 1237, 1262, 1268, 1299-1300, 1310-1316, 1359, 1373, 1393, 1483
plugins/search/static_stac_search.py            47       3  93.62%   39-40, 82
rest/__init__.py                                 1       0  100.00%
rest/core.py                                   193      18  90.67%   252, 275-277, 283-286, 318, 570, 572, 575-577, 649, 656-660
rest/server.py                                 299      54  81.94%   80-81, 107, 130-131, 242-244, 260, 300-301, 313-329, 415-420, 451, 612-619, 651, 694-695, 783-785, 802-807, 837, 839, 843-844, 848-849
rest/stac.py                                   436      95  78.21%   59-61, 229-231, 273, 286-295, 314-320, 365, 402-404, 427, 462-463, 549-594, 639, 659-660, 840, 905-907, 1126, 1136-1148, 1161-1183, 1197-1242, 1401-1402
rest/types/__init__.py                           1       0  100.00%
rest/types/eodag_search.py                     185       9  95.14%   52-55, 231-235, 288, 291, 359
rest/types/stac_queryables.py                   30       2  93.33%   28, 114
rest/types/stac_search.py                      122      10  91.80%   48-51, 167, 182-184, 192, 196
rest/utils/__init__.py                         116      14  87.93%   53, 108-109, 128-130, 180, 190-204, 236
rest/utils/cql_evaluate.py                      48       5  89.58%   69, 76, 90, 97, 105
rest/utils/rfc3339.py                           31       3  90.32%   78, 90, 92
types/__init__.py                               76       6  92.11%   53, 87, 152, 172, 177, 185
types/bbox.py                                   43      19  55.81%   46-61, 72-74, 85-87, 99-101, 113-115, 123
types/download_args.py                           9       0  100.00%
types/queryables.py                             81       0  100.00%
types/search_args.py                            70      18  74.29%   60-64, 71-88, 104
types/whoosh.py                                 15       0  100.00%
utils/__init__.py                              496      43  91.33%   83, 88, 109-111, 189-190, 199-226, 229, 243, 325-329, 405-409, 430-432, 514, 519, 529, 567-568, 964-967, 975-976, 1017-1018, 1098, 1182, 1200, 1375
utils/constraints.py                           123      42  65.85%   31, 84-93, 134, 139, 143, 154, 177-178, 189-197, 206, 220-236, 245-256
utils/exceptions.py                             37       2  94.59%   23, 93
utils/import_system.py                          30      20  33.33%   27, 67-81, 93-103
utils/logging.py                                29       1  96.55%   123
utils/notebook.py                               44      23  47.73%   25-29, 36-41, 58-62, 72-78, 83-87
utils/stac_reader.py                            91      28  69.23%   55-56, 63-86, 93-95, 99, 141, 155-158
TOTAL                                         8691    1535  82.34%
```

</details>


### Diff against develop

```
Filename                                 Stmts    Miss  Cover
-------------------------------------  -------  ------  -------
plugins/authentication/base.py               0      +1  -5.26%
plugins/download/http.py                   +15      +1  +0.47%
plugins/search/build_search_result.py       +1       0  +0.07%
plugins/search/qssearch.py                  +1      +1  -0.16%
rest/core.py                               +24      +8  -3.41%
rest/server.py                              +1       0  +0.06%
utils/__init__.py                           +1       0  +0.02%
TOTAL                                      +43     +11  -0.04%
```


Results for commit: 4142cd1296b4af91d62719d926266d28d50acd6f


_Minimum allowed coverage is `70%`_


:recycle: This comment has been updated with latest results


<!-- Sticky Pull Request Commentartifacts/unit-test-results-python3.12-ubuntu-latest/coverage.xml -->
github-actions[bot]: ![badge](https://raw.githubusercontent.com/CS-SI/eodag/_xml_coverage_reports_win/data/871-staging-status-in-server-mode-download/./badge.svg)


## Code Coverage (Windows)

<details>


```
Filename                                     Stmts    Miss  Cover    Missing
-----------------------------------------  -------  ------  -------  ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
__init__.py                                     11       0  100.00%
cli.py                                         300      47  84.33%   61, 647-686, 788-839, 843
config.py                                      318      28  91.19%   80-82, 91, 99, 103-105, 178, 190, 391-393, 457-460, 507-508, 517-518, 597, 631, 666-671, 673
crunch.py                                        6       6  0.00%    18-24
api/__init__.py                                  1       0  100.00%
api/core.py                                    727      76  89.55%   87-96, 369, 582, 626-629, 667, 772, 776-781, 807, 877, 954, 1068-1073, 1159-1171, 1211, 1213, 1217, 1238-1240, 1244-1255, 1268-1274, 1364-1367, 1396-1416, 1464, 1470-1473, 1482, 1848, 1881-1887, 2152, 2156-2159, 2173-2175, 2210
api/search_result.py                            44       6  86.36%   33-35, 70, 79, 86, 100
api/product/__init__.py                          6       0  100.00%
api/product/_assets.py                          44       5  88.64%   27-29, 79, 129
api/product/_product.py                        211      32  84.83%   53-60, 64-66, 170-177, 261-262, 352, 388, 449, 463-466, 479, 503-506, 549-555
api/product/metadata_mapping.py                649      83  87.21%   67-69, 130-132, 233, 265-266, 318-330, 332, 343, 349-361, 402-405, 442, 463-466, 489, 497-498, 571-572, 596-597, 603-606, 621-622, 771, 817, 934-939, 1070, 1084-1104, 1124, 1129, 1239, 1261, 1275, 1288-1307, 1346, 1398, 1421, 1436-1440, 1459
api/product/drivers/__init__.py                  6       0  100.00%
api/product/drivers/base.py                      8       2  75.00%   23, 41
plugins/__init__.py                              1       0  100.00%
plugins/base.py                                 23       4  82.61%   25, 48, 55, 68
plugins/manager.py                             127      14  88.98%   49-51, 95-100, 146, 185, 205, 231, 270-271
plugins/apis/__init__.py                         1       0  100.00%
plugins/apis/base.py                             4       0  100.00%
plugins/apis/ecmwf.py                           99      15  84.85%   47-55, 156-158, 205-206, 232-234
plugins/apis/usgs.py                           172      36  79.07%   59-64, 128, 201, 235, 270-272, 277, 303-304, 309, 339-346, 357-362, 384-390, 392-398, 421
plugins/authentication/__init__.py               7       1  85.71%   31
plugins/authentication/aws_auth.py              20       2  90.00%   25-27
plugins/authentication/base.py                  19       3  84.21%   26, 34, 47
plugins/authentication/generic.py               16       3  81.25%   28, 40, 50
plugins/authentication/header.py                17       1  94.12%   27
plugins/authentication/keycloak.py              88      17  80.68%   32-34, 159-160, 190-212, 238-243
plugins/authentication/oauth.py                 15       8  46.67%   25, 32-34, 38-41
plugins/authentication/openid_connect.py       103      64  37.86%   39-41, 138-150, 154-172, 180-222, 228-237, 246-286, 291-299, 304-305
plugins/authentication/qsauth.py                36       2  94.44%   32, 83
plugins/authentication/sas_auth.py              49       2  95.92%   32, 76
plugins/authentication/token.py                 81      13  83.95%   35-37, 86, 99, 101, 114-117, 165-168
plugins/crunch/__init__.py                       1       0  100.00%
plugins/crunch/base.py                          10       2  80.00%   25, 38
plugins/crunch/filter_date.py                   62      15  75.81%   30, 53-58, 72, 81, 90, 93, 105-107, 116-118, 125
plugins/crunch/filter_latest_intersect.py       50      35  30.00%   32-34, 48-53, 69-114
plugins/crunch/filter_latest_tpl_name.py        33       2  93.94%   28, 86
plugins/crunch/filter_overlap.py                68      17  75.00%   28-30, 33, 82-85, 91, 99, 110-126
plugins/crunch/filter_property.py               33       8  75.76%   29, 60-65, 68-69, 85-89
plugins/download/__init__.py                     1       0  100.00%
plugins/download/aws.py                        491     165  66.40%   77-83, 272, 285, 352-355, 369-373, 419-421, 425, 458-459, 465-469, 502, 537, 541, 548, 578-586, 590, 628-636, 643-645, 686-760, 778-839, 850-855, 871-884, 913, 928-930, 933, 943-951, 959-972, 982-1001, 1008-1020, 1061, 1087, 1132-1134, 1354
plugins/download/base.py                       261      59  77.39%   58-64, 145, 180, 250-252, 319-320, 340-346, 377-381, 387-388, 432, 435-449, 461, 465, 538-542, 572-573, 581-598, 605-613, 615-619, 666, 689, 711, 719
plugins/download/creodias_s3.py                 17       9  47.06%   44-58
plugins/download/http.py                       458      94  79.48%   82-88, 122, 196-208, 211, 292-297, 321, 323, 387, 414-416, 426, 432, 434, 458, 497-501, 558, 644-700, 718, 751-760, 786-787, 814, 838, 846-851, 873-874, 881, 942-948, 1003-1004, 1010, 1020, 1086, 1090, 1104-1120
plugins/download/s3rest.py                     117      27  76.92%   55-58, 124, 165, 199, 229-236, 239-241, 245, 258-264, 272-273, 276-280, 303, 324-327
plugins/search/__init__.py                       1       0  100.00%
plugins/search/base.py                         127       9  92.91%   49-54, 108, 112, 275, 295, 378
plugins/search/build_search_result.py          179      29  83.80%   62, 97, 142-143, 149, 160, 290-293, 327, 384-396, 458, 461, 471, 488, 508-523
plugins/search/creodias_s3.py                   54       3  94.44%   55, 73, 107
plugins/search/csw.py                          107      83  22.43%   43-45, 57-58, 62-63, 74-122, 128-141, 149-181, 199-240
plugins/search/data_request_search.py          198      65  67.17%   52, 89-92, 108, 120, 124-125, 139, 144, 149, 156, 169-172, 226-227, 231, 241-247, 252, 280-283, 291-302, 319, 321, 328-329, 331-332, 350-354, 387, 394, 405, 418, 424-436, 441
plugins/search/qssearch.py                     561      89  84.14%   89, 361-367, 375-376, 483-489, 544-547, 620-621, 662, 680, 695, 748, 769, 772-773, 782, 793, 802, 825, 885-890, 894-895, 923, 994, 1013-1030, 1069, 1145-1149, 1215-1216, 1237, 1262, 1268, 1299-1300, 1310-1316, 1359, 1373, 1393, 1443-1512
plugins/search/static_stac_search.py            47       3  93.62%   39-40, 82
rest/__init__.py                                 1       0  100.00%
rest/core.py                                   193      82  57.51%   149, 151, 153, 159-160, 177-185, 191-197, 244-320, 474-501, 519, 569-608, 649, 656-660
rest/server.py                                 299     299  0.00%    18-862
rest/stac.py                                   436     154  64.68%   59-61, 214, 229-231, 273, 286-295, 314-320, 365, 402-404, 427, 462-463, 549-594, 639, 647-648, 652-660, 782, 840, 905-907, 924-926, 934-936, 949-951, 965-982, 992-1013, 1023-1045, 1053-1070, 1093-1116, 1126, 1136-1148, 1161-1183, 1197-1242, 1395-1421
rest/types/__init__.py                           1       0  100.00%
rest/types/eodag_search.py                     185      18  90.27%   52-55, 231-235, 268-270, 288, 291, 297, 301, 359, 371-374
rest/types/stac_queryables.py                   30       6  80.00%   28, 53-58, 114
rest/types/stac_search.py                      122      12  90.16%   48-51, 167, 182-184, 192, 196, 240, 243
rest/utils/__init__.py                         116      31  73.28%   53, 79-85, 105, 108-109, 128-130, 147, 173-181, 188-209, 236
rest/utils/cql_evaluate.py                      48       5  89.58%   69, 76, 90, 97, 105
rest/utils/rfc3339.py                           31       5  83.87%   73-74, 78, 90, 92
types/__init__.py                               76      11  85.53%   53, 87, 125, 152, 162-164, 172, 177, 185, 195
types/bbox.py                                   43      19  55.81%   46-61, 72-74, 85-87, 99-101, 113-115, 123
types/download_args.py                           9       0  100.00%
types/queryables.py                             81       0  100.00%
types/search_args.py                            70      18  74.29%   60-64, 71-88, 104
types/whoosh.py                                 15       0  100.00%
utils/__init__.py                              496      44  91.13%   83, 88, 109-111, 189-190, 199-226, 229, 243, 325-329, 405-409, 430-432, 514, 519, 529, 567-568, 964-967, 975-976, 1017-1018, 1098, 1181-1182, 1200, 1375
utils/constraints.py                           123      42  65.85%   31, 84-93, 134, 139, 143, 154, 177-178, 189-197, 206, 220-236, 245-256
utils/exceptions.py                             37       2  94.59%   23, 93
utils/import_system.py                          30      20  33.33%   27, 67-81, 93-103
utils/logging.py                                29       1  96.55%   123
utils/notebook.py                               44      23  47.73%   25-29, 36-41, 58-62, 72-78, 83-87
utils/stac_reader.py                            91      28  69.23%   55-56, 63-86, 93-95, 99, 141, 155-158
TOTAL                                         8691    2004  76.94%
```

</details>


### Diff against develop

```
Filename                                 Stmts    Miss  Cover
-------------------------------------  -------  ------  --------
plugins/download/http.py                   +15      +1  +0.47%
plugins/search/build_search_result.py       +1       0  +0.09%
plugins/search/qssearch.py                  +1      +1  -0.15%
rest/core.py                               +24     +21  -6.40%
rest/server.py                              +1      +1  +100.00%
utils/__init__.py                           +1       0  +0.02%
TOTAL                                      +43     +24  -0.16%
```


Results for commit: 4142cd1296b4af91d62719d926266d28d50acd6f


_Minimum allowed coverage is `70%`_


:recycle: This comment has been updated with latest results


<!-- Sticky Pull Request Commentartifacts/unit-test-results-python3.12-windows-latest/coverage.xml -->

Patch:
diff --git a/eodag/plugins/download/http.py b/eodag/plugins/download/http.py
index 140f1e12..c1b03a36 100644
--- a/eodag/plugins/download/http.py
+++ b/eodag/plugins/download/http.py
@@ -130,7 +130,7 @@ class HTTPDownload(Download):
         product: EOProduct,
         auth: Optional[AuthBase] = None,
         **kwargs: Unpack[DownloadConf],
-    ) -> None:
+    ) -> Optional[Dict[str, Any]]:
         """Send product order request.
 
         It will be executed once before the download retry loop, if the product is OFFLINE
@@ -156,6 +156,8 @@ class HTTPDownload(Download):
         :type auth: Optional[AuthBase]
         :param kwargs: download additional kwargs
         :type kwargs: Union[str, bool, dict]
+        :returns: the returned json status response
+        :rtype: dict
         """
         product.properties["storageStatus"] = STAGING_STATUS
 
@@ -205,15 +207,20 @@ class HTTPDownload(Download):
                 )
                 self._check_auth_exception(e)
 
-            self.order_response_process(response, product)
+            return self.order_response_process(response, product)
+        return None
 
-    def order_response_process(self, response: Response, product: EOProduct) -> None:
+    def order_response_process(
+        self, response: Response, product: EOProduct
+    ) -> Optional[Dict[str, Any]]:
         """Process order response
 
         :param response: The order response
         :type response: :class:`~requests.Response`
         :param product: The orderd EO product
         :type product: :class:`~eodag.api.product._product.EOProduct`
+        :returns: the returned json status response
+        :rtype: dict
         """
         order_metadata_mapping = getattr(self.config, "order_on_response", {}).get(
             "metadata_mapping", {}
@@ -223,8 +230,11 @@ class HTTPDownload(Download):
             order_metadata_mapping_jsonpath = mtd_cfg_as_conversion_and_querypath(
                 order_metadata_mapping,
             )
+
+            json_response = response.json()
+
             properties_update = properties_from_json(
-                response.json(),
+                json_response,
                 order_metadata_mapping_jsonpath,
             )
             properties_update = {
@@ -235,8 +245,12 @@ class HTTPDownload(Download):
                 product.remote_location = product.location = product.properties[
                     "downloadLink"
                 ]
+                product.properties["storageStatus"] = ONLINE_STATUS
                 logger.debug(f"Product location updated to {product.location}")
 
+            return json_response
+        return None
+
     def orderDownloadStatus(
         self,
         product: EOProduct,
@@ -582,6 +596,19 @@ class HTTPDownload(Download):
             )
         return stream_size
 
+    def _check_product_filename(self, product: EOProduct) -> str:
+        filename = None
+        asset_content_disposition = self.stream.headers.get("content-disposition", None)
+        if asset_content_disposition:
+            filename = cast(
+                Optional[str],
+                parse_header(asset_content_disposition).get_param("filename", None),
+            )
+        if not filename:
+            # default filename extracted from path
+            filename = os.path.basename(self.stream.url)
+        return filename
+
     def _stream_download_dict(
         self,
         product: EOProduct,
@@ -823,7 +850,11 @@ class HTTPDownload(Download):
                         product.properties["storageStatus"] = "ORDERED"
                         self._process_exception(None, product, ordered_message)
                 stream_size = self._check_stream_size(product) or None
+                filename = self._check_product_filename(product) or None
                 product.headers = self.stream.headers
+                product.headers[
+                    "content-disposition"
+                ] = f"attachment; filename={filename}"
                 progress_callback.reset(total=stream_size)
                 for chunk in self.stream.iter_content(chunk_size=64 * 1024):
                     if chunk:
diff --git a/eodag/plugins/search/build_search_result.py b/eodag/plugins/search/build_search_result.py
index 396b5dd0..8e5f9e9e 100644
--- a/eodag/plugins/search/build_search_result.py
+++ b/eodag/plugins/search/build_search_result.py
@@ -175,8 +175,9 @@ class BuildPostSearchResult(PostJsonSearch):
 
         query_hash = hashlib.sha1(str(qs).encode("UTF-8")).hexdigest()
 
-        # update result with search args if not None (and not auth)
+        # update result with product_type_def_params and search args if not None (and not auth)
         kwargs.pop("auth", None)
+        result.update(self.product_type_def_params)
         result = dict(result, **{k: v for k, v in kwargs.items() if v is not None})
 
         # parse porperties
diff --git a/eodag/plugins/search/qssearch.py b/eodag/plugins/search/qssearch.py
index 7c97fc86..9e8c5a2d 100644
--- a/eodag/plugins/search/qssearch.py
+++ b/eodag/plugins/search/qssearch.py
@@ -1144,6 +1144,11 @@ class PostJsonSearch(QueryStringSearch):
         if _dc_qs is not None:
             qs = unquote_plus(unquote_plus(_dc_qs))
             qp = geojson.loads(qs)
+
+            # provider product type specific conf
+            self.product_type_def_params = self.get_product_type_def_params(
+                product_type, **kwargs
+            )
         else:
             keywords = {
                 k: v for k, v in kwargs.items() if k != "auth" and v is not None
diff --git a/eodag/rest/core.py b/eodag/rest/core.py
index 729e8f99..df5aa6c6 100644
--- a/eodag/rest/core.py
+++ b/eodag/rest/core.py
@@ -15,20 +15,28 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
+from __future__ import annotations
+
 import datetime
 import logging
 import os
 import re
-from typing import Any, Callable, Dict, List, Optional, cast
+from typing import TYPE_CHECKING, cast
+from unittest.mock import Mock
 
 import dateutil
-from fastapi import Request
-from fastapi.responses import StreamingResponse
+from fastapi.responses import ORJSONResponse, StreamingResponse
 from pydantic import ValidationError as pydanticValidationError
+from requests.models import Response as RequestsResponse
 
 import eodag
 from eodag import EOProduct
-from eodag.api.product.metadata_mapping import OSEO_METADATA_MAPPING
+from eodag.api.product.metadata_mapping import (
+    NOT_AVAILABLE,
+    ONLINE_STATUS,
+    OSEO_METADATA_MAPPING,
+    STAGING_STATUS,
+)
 from eodag.api.search_result import SearchResult
 from eodag.config import load_stac_config
 from eodag.plugins.crunch.filter_latest_intersect import FilterLatestIntersect
@@ -37,7 +45,6 @@ from eodag.plugins.crunch.filter_overlap import FilterOverlap
 from eodag.rest.stac import StacCatalog, StacCollection, StacCommon, StacItem
 from eodag.rest.types.eodag_search import EODAGSearch
 from eodag.rest.types.stac_queryables import StacQueryableProperty, StacQueryables
-from eodag.rest.types.stac_search import SearchPostRequest
 from eodag.rest.utils import (
     Cruncher,
     file_to_stream,
@@ -51,6 +58,7 @@ from eodag.utils import (
     _deprecated,
     deepcopy,
     dict_items_recursive_apply,
+    urlencode,
 )
 from eodag.utils.exceptions import (
     MisconfiguredError,
@@ -59,6 +67,16 @@ from eodag.utils.exceptions import (
     ValidationError,
 )
 
+if TYPE_CHECKING:
+    from typing import Any, Callable, Dict, List, Optional, Union
+
+    from fastapi import Request
+    from requests.auth import AuthBase
+    from starlette.responses import Response
+
+    from eodag.rest.types.stac_search import SearchPostRequest
+
+
 eodag_api = eodag.EODataAccessGateway()
 
 logger = logging.getLogger("eodag.rest.core")
@@ -212,12 +230,13 @@ def search_stac_items(
 
 
 def download_stac_item(
+    request: Request,
     catalogs: List[str],
     item_id: str,
     provider: Optional[str] = None,
     asset: Optional[str] = None,
     **kwargs: Any,
-) -> StreamingResponse:
+) -> Response:
     """Download item
 
     :param catalogs: Catalogs list (only first is used as product_type)
@@ -229,7 +248,7 @@ def download_stac_item(
     :param kwargs: additional download parameters
     :type kwargs: Any
     :returns: a stream of the downloaded data (zip file)
-    :rtype: StreamingResponse
+    :rtype: Response
     """
     product_type = catalogs[0]
 
@@ -243,12 +262,19 @@ def download_stac_item(
             f"Could not find {item_id} item in {product_type} collection"
             + (f" for provider {provider}" if provider else "")
         )
+    auth = product.downloader_auth.authenticate()
 
     try:
+        _order_and_update(product, auth, **kwargs)
+
         download_stream = cast(
             StreamResponse,
             product.downloader._stream_download_dict(
-                product, auth=product.downloader_auth.authenticate(), asset=asset
+                product,
+                auth=auth,
+                asset=asset,
+                wait=-1,
+                timeout=-1,
             ),
         )
     except NotImplementedError:
@@ -259,6 +285,19 @@ def download_stac_item(
         download_stream = file_to_stream(
             eodag_api.download(product, extract=False, asset=asset)
         )
+    except NotAvailableError:
+        if product.properties.get("storageStatus") != ONLINE_STATUS:
+            download_link = f"{request.state.url}?{urlencode(dict(kwargs, **{'provider': provider}), doseq=True)}"
+            return ORJSONResponse(
+                status_code=202,
+                headers={"Location": download_link},
+                content={
+                    "description": "Product is not available yet, please try again using given updated location",
+                    "location": download_link,
+                },
+            )
+        else:
+            raise
 
     return StreamingResponse(
         content=download_stream.content,
@@ -267,6 +306,40 @@ def download_stac_item(
     )
 
 
+def _order_and_update(
+    product: EOProduct, auth: Union[AuthBase, Dict[str, str]], **kwargs: Any
+) -> None:
+    """Order product if needed and update given kwargs with order-status-dict"""
+    if product.properties.get("storageStatus") != ONLINE_STATUS and hasattr(
+        product.downloader, "order_response_process"
+    ):
+        # update product (including orderStatusLink) if product was previously ordered
+        logger.debug("Use given download query arguments to parse order link")
+        response = Mock(spec=RequestsResponse)
+        response.status_code = 200
+        response.json.return_value = kwargs
+        product.downloader.order_response_process(response, product)
+
+    if (
+        product.properties.get("storageStatus") != ONLINE_STATUS
+        and NOT_AVAILABLE in product.properties.get("orderStatusLink", "")
+        and hasattr(product.downloader, "orderDownload")
+    ):
+        # first order
+        logger.debug("Order product")
+        order_status_dict = product.downloader.orderDownload(product=product, auth=auth)
+        kwargs.update(order_status_dict or {})
+
+    if product.properties.get("storageStatus") == STAGING_STATUS and hasattr(
+        product.downloader, "orderDownloadStatus"
+    ):
+        # check order status if needed
+        logger.debug("Checking product order status")
+        product.downloader.orderDownloadStatus(product=product, auth=auth)
+        if product.properties.get("storageStatus") != ONLINE_STATUS:
+            raise NotAvailableError("Product is not available yet")
+
+
 def get_detailled_collections_list(
     provider: Optional[str] = None, fetch_providers: bool = True
 ) -> List[Dict[str, Any]]:
diff --git a/eodag/rest/server.py b/eodag/rest/server.py
index 3aedb6a9..21139461 100755
--- a/eodag/rest/server.py
+++ b/eodag/rest/server.py
@@ -39,7 +39,7 @@ from fastapi import FastAPI, HTTPException, Request
 from fastapi.encoders import jsonable_encoder
 from fastapi.middleware.cors import CORSMiddleware
 from fastapi.openapi.utils import get_openapi
-from fastapi.responses import ORJSONResponse, StreamingResponse
+from fastapi.responses import ORJSONResponse
 from pydantic import ValidationError as pydanticValidationError
 from pygeofilter.backends.cql2_json import to_cql2
 from pygeofilter.parsers.cql2_text import parse as parse_cql2_text
@@ -80,6 +80,8 @@ if TYPE_CHECKING:
     from fastapi.types import DecoratedCallable
     from requests import Response
 
+from starlette.responses import Response as StarletteResponse
+
 logger = logging.getLogger("eodag.rest.server")
 ERRORS_WITH_500_STATUS_CODE = {
     "MisconfiguredError",
@@ -385,7 +387,7 @@ def stac_extension_oseo(request: Request) -> Any:
 )
 def stac_collections_item_download(
     collection_id: str, item_id: str, request: Request
-) -> StreamingResponse:
+) -> StarletteResponse:
     """STAC collection item download"""
     logger.debug("URL: %s", request.url)
 
@@ -393,7 +395,11 @@ def stac_collections_item_download(
     provider = arguments.pop("provider", None)
 
     return download_stac_item(
-        catalogs=[collection_id], item_id=item_id, provider=provider, **arguments
+        request=request,
+        catalogs=[collection_id],
+        item_id=item_id,
+        provider=provider,
+        **arguments,
     )
 
 
@@ -412,6 +418,7 @@ def stac_collections_item_download_asset(
     provider = arguments.pop("provider", None)
 
     return download_stac_item(
+        request=request,
         catalogs=[collection_id],
         item_id=item_id,
         provider=provider,
@@ -575,7 +582,7 @@ def collections(request: Request) -> Any:
 )
 def stac_catalogs_item_download(
     catalogs: str, item_id: str, request: Request
-) -> StreamingResponse:
+) -> StarletteResponse:
     """STAC Catalog item download"""
     logger.debug("URL: %s", request.url)
 
@@ -585,7 +592,11 @@ def stac_catalogs_item_download(
     list_catalog = catalogs.strip("/").split("/")
 
     return download_stac_item(
-        catalogs=list_catalog, item_id=item_id, provider=provider, **arguments
+        request=request,
+        catalogs=list_catalog,
+        item_id=item_id,
+        provider=provider,
+        **arguments,
     )
 
 
@@ -606,6 +617,7 @@ def stac_catalogs_item_download_asset(
     list_catalog = catalogs.strip("/").split("/")
 
     return download_stac_item(
+        request=request,
         catalogs=list_catalog,
         item_id=item_id,
         provider=provider,
diff --git a/eodag/utils/__init__.py b/eodag/utils/__init__.py
index 6471d0db..b46a838a 100644
--- a/eodag/utils/__init__.py
+++ b/eodag/utils/__init__.py
@@ -1433,6 +1433,7 @@ class StreamResponse:
     content: Iterator[bytes]
     headers: Optional[Mapping[str, str]] = None
     media_type: Optional[str] = None
+    status_code: Optional[int] = None
 
 
 def guess_file_type(file: str) -> Optional[str]:


Test patch:
diff --git a/tests/__init__.py b/tests/__init__.py
index 2bd14e8a..59ce5692 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -335,6 +335,7 @@ class EODagTestCase(unittest.TestCase):
                     response.__zip_buffer = io.BytesIO(fh.read())
                 cl = response.__zip_buffer.getbuffer().nbytes
                 response.headers = {"content-length": cl}
+                response.url = "http://foo.bar"
 
             def __enter__(response):
                 return response
diff --git a/tests/context.py b/tests/context.py
index 2e6aeec7..f697bb45 100644
--- a/tests/context.py
+++ b/tests/context.py
@@ -33,6 +33,7 @@ from eodag.api.product.metadata_mapping import (
     format_metadata,
     OFFLINE_STATUS,
     ONLINE_STATUS,
+    STAGING_STATUS,
     properties_from_json,
     NOT_AVAILABLE,
 )
diff --git a/tests/units/test_download_plugins.py b/tests/units/test_download_plugins.py
index 832c63f7..3f2f79ef 100644
--- a/tests/units/test_download_plugins.py
+++ b/tests/units/test_download_plugins.py
@@ -172,6 +172,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
                     self.__zip_buffer = io.BytesIO(fh.read())
                 cl = self.__zip_buffer.getbuffer().nbytes
                 self.headers = {"content-length": cl}
+                self.url = "http://foo.bar"
 
             def __enter__(self):
                 return self
@@ -1008,12 +1009,12 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
         # empty product download directory should have been removed
         self.assertFalse(Path(os.path.join(self.output_dir, "dummy_product")).exists())
 
-    def test_plugins_download_http_order_download_cds(
+    def test_plugins_download_http_order_download_cop_ads(
         self,
     ):
         """HTTPDownload.download must order the product if needed"""
 
-        self.product.provider = "cop_cds"
+        self.product.provider = "cop_ads"
         self.product.product_type = "CAMS_EAC4"
         product_dataset = "cams-global-reanalysis-eac4"
 
@@ -1075,6 +1076,7 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
 
             # expected values
             expected_remote_location = "http://somewhere/download/dummy_request_id"
+            expected_order_status_link = f"{endpoint}/tasks/dummy_request_id"
             expected_path = os.path.join(
                 output_data_path, self.product.properties["title"]
             )
@@ -1085,6 +1087,12 @@ class TestDownloadPluginHttp(BaseDownloadPluginTest):
                 timeout=0.2 / 60,
             )
             self.assertEqual(self.product.remote_location, expected_remote_location)
+            self.assertEqual(
+                self.product.properties["downloadLink"], expected_remote_location
+            )
+            self.assertEqual(
+                self.product.properties["orderStatusLink"], expected_order_status_link
+            )
             self.assertEqual(path, expected_path)
             self.assertEqual(self.product.location, path_to_uri(expected_path))
 
diff --git a/tests/units/test_http_server.py b/tests/units/test_http_server.py
index 9571d73f..5d72bed1 100644
--- a/tests/units/test_http_server.py
+++ b/tests/units/test_http_server.py
@@ -25,7 +25,7 @@ import unittest
 from pathlib import Path
 from tempfile import TemporaryDirectory
 from typing import Any, Dict, List, Optional, Union
-from unittest.mock import Mock
+from unittest.mock import MagicMock, Mock
 
 import geojson
 import httpx
@@ -36,11 +36,15 @@ from eodag.config import PluginConfig
 from eodag.plugins.authentication.base import Authentication
 from eodag.plugins.download.base import Download
 from eodag.utils import USER_AGENT, MockResponse, StreamResponse
-from eodag.utils.exceptions import TimeOutError
+from eodag.utils.exceptions import NotAvailableError, TimeOutError
 from tests import mock
 from tests.context import (
     DEFAULT_ITEMS_PER_PAGE,
     HTTP_REQ_TIMEOUT,
+    NOT_AVAILABLE,
+    OFFLINE_STATUS,
+    ONLINE_STATUS,
+    STAGING_STATUS,
     TEST_RESOURCES_PATH,
     AuthenticationError,
     SearchResult,
@@ -436,6 +440,13 @@ class RequestTestCase(unittest.TestCase):
         self.assertIn("description", response_content)
         self.assertIn("NotAvailableError", response_content["description"])
 
+    def _request_accepted(self, url: str):
+        response = self.app.get(url, follow_redirects=True)
+        response_content = json.loads(response.content.decode("utf-8"))
+        self.assertEqual(202, response.status_code)
+        self.assertIn("description", response_content)
+        self.assertIn("location", response_content)
+
     def test_request_params(self):
         self._request_not_valid(f"search?collections={self.tested_product_type}&bbox=1")
         self._request_not_valid(
@@ -1047,6 +1058,10 @@ class RequestTestCase(unittest.TestCase):
         response_filename = header_content_disposition.get_param("filename", None)
         self.assertEqual(response_filename, expected_file)
 
+    @mock.patch(
+        "eodag.plugins.authentication.base.Authentication.authenticate",
+        autospec=True,
+    )
     @mock.patch(
         "eodag.plugins.download.base.Download._stream_download_dict",
         autospec=True,
@@ -1056,7 +1071,7 @@ class RequestTestCase(unittest.TestCase):
         autospec=True,
     )
     def test_download_item_from_collection_no_stream(
-        self, mock_download: Mock, mock_stream_download: Mock
+        self, mock_download: Mock, mock_stream_download: Mock, mock_auth: Mock
     ):
         """Download through eodag server catalog should return a valid response"""
         # download should be performed locally then deleted if streaming is not available
@@ -1073,6 +1088,71 @@ class RequestTestCase(unittest.TestCase):
             expected_file
         ), f"File {expected_file} should have been deleted"
 
+    @mock.patch(
+        "eodag.rest.core.eodag_api.search",
+        autospec=True,
+    )
+    def test_download_offline_item_from_catalog(self, mock_search):
+        """Download an offline item through eodag server catalog should return a
+        response with HTTP Status 202"""
+        # mock_search_result returns 2 search results, only keep one
+        two_results = self.mock_search_result()
+        product = two_results[0][0]
+        mock_search.return_value = (
+            [
+                product,
+            ],
+            1,
+        )
+        product.downloader_auth = MagicMock()
+        product.downloader.orderDownload = MagicMock()
+        product.downloader.orderDownloadStatus = MagicMock()
+        product.downloader.order_response_process = MagicMock()
+        product.downloader._stream_download_dict = MagicMock(
+            side_effect=NotAvailableError("Product offline. Try again later.")
+        )
+        product.properties["orderStatusLink"] = f"{NOT_AVAILABLE}?foo=bar"
+
+        # ONLINE product with error
+        product.properties["storageStatus"] = ONLINE_STATUS
+        # status 404 and no order try
+        self._request_not_found(
+            f"catalogs/{self.tested_product_type}/items/foo/download"
+        )
+        product.downloader.orderDownload.assert_not_called()
+        product.downloader.orderDownloadStatus.assert_not_called()
+        product.downloader.order_response_process.assert_not_called()
+        product.downloader._stream_download_dict.assert_called_once()
+        product.downloader._stream_download_dict.reset_mock()
+
+        # OFFLINE product with error
+        product.properties["storageStatus"] = OFFLINE_STATUS
+        # status 202 and order once and no status check
+        self._request_accepted(
+            f"catalogs/{self.tested_product_type}/items/foo/download"
+        )
+        product.downloader.orderDownload.assert_called_once()
+        product.downloader.orderDownload.reset_mock()
+        product.downloader.orderDownloadStatus.assert_not_called()
+        product.downloader.order_response_process.assert_called()
+        product.downloader.order_response_process.reset_mock()
+        product.downloader._stream_download_dict.assert_called_once()
+        product.downloader._stream_download_dict.reset_mock()
+
+        # STAGING product and available orderStatusLink
+        product.properties["storageStatus"] = STAGING_STATUS
+        product.properties["orderStatusLink"] = "http://somewhere?foo=bar"
+        # status 202 and no order but status checked and no download try
+        self._request_accepted(
+            f"catalogs/{self.tested_product_type}/items/foo/download"
+        )
+        product.downloader.orderDownload.assert_not_called()
+        product.downloader.orderDownloadStatus.assert_called_once()
+        product.downloader.orderDownloadStatus.reset_mock()
+        product.downloader.order_response_process.assert_called()
+        product.downloader.order_response_process.reset_mock()
+        product.downloader._stream_download_dict.assert_not_called()
+
     def test_conformance(self):
         """Request to /conformance should return a valid response"""
         self._request_valid("conformance", check_links=False)