@@ -857,10 +857,10 @@ def parameter_hoisting_note(method: str,
857
857
def repository_search_spec (* , post : bool ):
858
858
id_spec_link = '#operations-Index-get_index__entity_type___entity_id_'
859
859
return {
860
- 'summary' : fd ( f'''
861
- Search an index for entities of interest
862
- { ", with filters provided in the request body" if post else "" } .
863
- ''' ),
860
+ 'summary' : (
861
+ ' Search an index for entities of interest' +
862
+ iif ( post , ', with large parameters provided in the request body' )
863
+ ),
864
864
'deprecated' : post ,
865
865
'description' :
866
866
iif (post , parameter_hoisting_note ('GET' , '/index/files' , 'POST' ) + fd ('''
@@ -1096,14 +1096,34 @@ def get_summary():
1096
1096
authentication = request .authentication )
1097
1097
1098
1098
1099
- def manifest_route (* , fetch : bool , initiate : bool ):
1099
+ post_manifest_example_url = (
1100
+ f'{ app .base_url } /manifest/files'
1101
+ f'?catalog={ list (config .catalogs .keys ())[0 ]} '
1102
+ '&filters={…}'
1103
+ f'&format={ app .metadata_plugin .manifest_formats [0 ].value } '
1104
+ )
1105
+
1106
+
1107
+ def manifest_route (* , fetch : bool , initiate : bool , curl : bool = False ):
1108
+ if initiate :
1109
+ if curl :
1110
+ assert not fetch
1111
+ method = 'POST'
1112
+ else :
1113
+ method = 'PUT'
1114
+ else :
1115
+ assert not curl
1116
+ method = 'GET'
1100
1117
return app .route (
1101
1118
# The path parameter could be a token *or* an object key, but we don't
1102
1119
# want to complicate the API with this detail
1103
1120
('/fetch' if fetch else '' )
1104
1121
+ ('/manifest/files' if initiate else '/manifest/files/{token}' ),
1105
1122
# The initial PUT request is idempotent.
1106
- methods = ['PUT' if initiate else 'GET' ],
1123
+ methods = [method ],
1124
+ # In order to support requests made with `curl` and its `--data` option,
1125
+ # we accept the `application/x-www-form-urlencoded` content-type.
1126
+ content_types = ['application/json' , 'application/x-www-form-urlencoded' ],
1107
1127
interactive = fetch ,
1108
1128
cors = True ,
1109
1129
path_spec = None if initiate else {
@@ -1115,26 +1135,58 @@ def manifest_route(*, fetch: bool, initiate: bool):
1115
1135
},
1116
1136
spec = {
1117
1137
'tags' : ['Manifests' ],
1138
+ 'deprecated' : curl ,
1118
1139
'summary' :
1119
1140
(
1120
1141
'Initiate the preparation of a manifest'
1121
1142
if initiate else
1122
1143
'Determine status of a manifest preparation job'
1123
1144
) + (
1124
1145
' via XHR' if fetch else ''
1146
+ ) + (
1147
+ ' as an alternative to PUT for curl users' if curl else ''
1125
1148
),
1126
- 'description' : fd ('''
1127
- Create a manifest preparation job, returning either
1128
-
1129
- - a 301 redirect to the URL of the status of that job or
1149
+ 'description' : (
1150
+ fd ('''
1151
+ Create a manifest preparation job, returning either
1130
1152
1131
- - a 302 redirect to the URL of an already prepared manifest.
1153
+ - a 301 redirect to the URL of the status of that job or
1132
1154
1133
- This endpoint is not suitable for interactive use via the
1134
- Swagger UI. Please use [PUT /fetch/manifest/files][1] instead.
1155
+ - a 302 redirect to the URL of an already prepared manifest.
1156
+ ''' )
1157
+ + iif (not curl , fd (f'''
1158
+ This endpoint is not suitable for interactive use via the
1159
+ Swagger UI. Please use [{ method } /fetch/manifest/files][1]
1160
+ instead.
1135
1161
1136
- [1]: #operations-Manifests-put_fetch_manifest_files
1137
- ''' ) + parameter_hoisting_note ('PUT' , '/manifest/files' , 'PUT' )
1162
+ [1]: #operations-Manifests-{ method .lower ()} _fetch_manifest_files
1163
+ ''' ))
1164
+ + parameter_hoisting_note (method , '/manifest/files' , method )
1165
+ + iif (curl , fd (f'''
1166
+ Requests to this endpoint are idempotent, so PUT would be
1167
+ the more standards-compliant method to use. POST is offered
1168
+ as a convenience for `curl` users, exploiting the fact that
1169
+ `curl` drops to GET when following a redirect in response to
1170
+ a POST, but not a PUT request. This is the only reason for
1171
+ the deprecation of this endpoint and there are currently no
1172
+ plans to remove it.
1173
+
1174
+ To use this endpoint with `curl`, pass the `--location` and
1175
+ `--data` options. This makes `curl` automatically follow the
1176
+ intermediate redirects to the GET /manifest/files endpoint,
1177
+ and ultimately to the URL that yields the manifest. Example:
1178
+
1179
+ ```
1180
+ curl --data "" --location { post_manifest_example_url }
1181
+ ```
1182
+
1183
+ In order to facilitate this, a POST request to this endpoint
1184
+ may have a `Content-Type` header of
1185
+ `application/x-www-form-urlencoded`, which is what the
1186
+ `--data` option sends. The body must be empty in that case
1187
+ and parameters cannot be hoisted as described above.
1188
+ ''' ))
1189
+ )
1138
1190
if initiate and not fetch else
1139
1191
fd ('''
1140
1192
Check on the status of an ongoing manifest preparation job,
@@ -1150,15 +1202,17 @@ def manifest_route(*, fetch: bool, initiate: bool):
1150
1202
instead.
1151
1203
1152
1204
[1]: #operations-Manifests-get_fetch_manifest_files__token_
1153
- ''' ) if not initiate and not fetch else fd ('''
1205
+ ''' )
1206
+ if not initiate and not fetch else
1207
+ fd (f'''
1154
1208
Create a manifest preparation job, returning a 200 status
1155
1209
response whose JSON body emulates the HTTP headers that would be
1156
- found in a response to an equivalent request to the [PUT
1210
+ found in a response to an equivalent request to the [{ method }
1157
1211
/manifest/files][1] endpoint.
1158
1212
1159
1213
Whenever client-side JavaScript code is used in a web
1160
1214
application to request the preparation of a manifest from Azul,
1161
- this endpoint should be used instead of [PUT
1215
+ this endpoint should be used instead of [{ method }
1162
1216
/manifest/files][1]. This way, the client can use XHR to make
1163
1217
the request, retaining full control over the handling of
1164
1218
redirects and enabling the client to bypass certain limitations
@@ -1168,8 +1222,9 @@ def manifest_route(*, fetch: bool, initiate: bool):
1168
1222
upper limit on the number of consecutive redirects, before the
1169
1223
manifest generation job is done.
1170
1224
1171
- [1]: #operations-Manifests-put_manifest_files
1172
- ''' ) + parameter_hoisting_note ('PUT' , '/fetch/manifest/files' , 'PUT' )
1225
+ [1]: #operations-Manifests-{ method .lower ()} _manifest_files
1226
+ ''' )
1227
+ + parameter_hoisting_note (method , '/fetch/manifest/files' , method )
1173
1228
if initiate and fetch else
1174
1229
fd ('''
1175
1230
Check on the status of an ongoing manifest preparation job,
@@ -1314,10 +1369,10 @@ def manifest_route(*, fetch: bool, initiate: bool):
1314
1369
1315
1370
For a detailed description of these properties see the
1316
1371
documentation for the respective response headers
1317
- documented under ''' ) + (fd ('''
1318
- [PUT /manifest/files][1].
1372
+ documented under ''' ) + (fd (f '''
1373
+ [{ method } /manifest/files][1].
1319
1374
1320
- [1]: #operations-Manifests-put_manifest_files
1375
+ [1]: #operations-Manifests-{ method . lower () } _manifest_files
1321
1376
''' ) if initiate else fd ('''
1322
1377
[GET /manifest/files/{token}][1].
1323
1378
@@ -1359,6 +1414,7 @@ def manifest_route(*, fetch: bool, initiate: bool):
1359
1414
)
1360
1415
1361
1416
1417
+ @manifest_route (fetch = False , initiate = True , curl = True )
1362
1418
@manifest_route (fetch = False , initiate = True )
1363
1419
def file_manifest ():
1364
1420
return _file_manifest (fetch = False )
@@ -1381,6 +1437,14 @@ def fetch_file_manifest_with_token(token: str):
1381
1437
1382
1438
def _file_manifest (fetch : bool , token_or_key : str | None = None ):
1383
1439
request = app .current_request
1440
+ post = request .method == 'POST'
1441
+ if (
1442
+ post
1443
+ and request .headers .get ('content-type' ) == 'application/x-www-form-urlencoded'
1444
+ and request .raw_body != b''
1445
+ ):
1446
+ raise BRE ('The body must be empty for a POST request of content-type '
1447
+ '`application/x-www-form-urlencoded` to this endpoint' )
1384
1448
query_params = request .query_params or {}
1385
1449
_hoist_parameters (query_params , request )
1386
1450
if token_or_key is None :
0 commit comments