Olof hagsand 2021-11-09 17:38:17 +01:00
parent baa6e821a8
commit a4b4dc97ce
28 changed files with 1011 additions and 527 deletions

View file

@ -519,7 +519,7 @@ get_list_pagination(clicon_handle h,
}
}
/* sort */
if (ret && (x = xml_find_type(xe, NULL, "sort", CX_ELMNT)) != NULL)
if (ret && (x = xml_find_type(xe, NULL, "sort-by", CX_ELMNT)) != NULL)
sort = xml_body(x);
if (sort) {
/* XXX: nothing yet */
@ -721,12 +721,9 @@ get_common(clicon_handle h,
char *xpath0;
cbuf *cbreason = NULL;
int list_pagination = 0;
char *valstr;
cxobj *x;
#if 1
cxobj **xvec = NULL;
size_t xlen;
#endif
cxobj **xvec = NULL;
size_t xlen;
cxobj *xlistpag;
clicon_debug(1, "%s", __FUNCTION__);
username = clicon_username_get(h);
@ -767,15 +764,15 @@ get_common(clicon_handle h,
}
}
/* Check if list pagination */
if ((x = xml_find_type(xe, NULL, "list-pagination", CX_ELMNT)) != NULL &&
(valstr = xml_body(x)) != NULL &&
strcmp(valstr,"true")==0)
if ((xlistpag = xml_find_type(xe, NULL, "list-pagination", CX_ELMNT)) != NULL)
list_pagination = 1;
/* Sanity check for list pagination: path must be a list/leaf-list, if it is,
* check config/state
*/
if (list_pagination){
if (get_list_pagination(h, ce, xe, content, db,
if (get_list_pagination(h, ce,
xlistpag,
content, db,
depth, yspec, xpath, nsc, username,
cbret) < 0)
goto done;

View file

@ -46,15 +46,17 @@ extern "C" {
*/
/*! RESTCONF media types
* @see http_media_map
* @note DUPLICATED in clixon_lib.h
* @note DUPLICATED in restconf_lib.h
*/
enum restconf_media{
YANG_DATA_JSON, /* "application/yang-data+json" */
YANG_DATA_XML, /* "application/yang-data+xml" */
YANG_PATCH_JSON, /* "application/yang-patch+json" */
YANG_PATCH_XML, /* "application/yang-patch+xml" */
YANG_COLLECTION_XML, /* draft-wwlh-netconf-list-pagination-rc-01.txt */
YANG_COLLECTION_JSON /* draft-wwlh-netconf-list-pagination-rc-01.txt */
YANG_PAGINATION_XML, /* draft-wwlh-netconf-list-pagination-rc-02.txt */
/* For JSON, the existing "application/yang-data+json" media type is
sufficient, as the JSON format has built-in support for encoding
arrays. */
};
typedef enum restconf_media restconf_media;

View file

@ -275,7 +275,7 @@ api_return_err(clicon_handle h,
switch (media){
case YANG_DATA_XML:
case YANG_PATCH_XML:
case YANG_COLLECTION_XML:
case YANG_PAGINATION_XML:
clicon_debug(1, "%s code:%d", __FUNCTION__, code);
if (pretty){
cprintf(cb, " <errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">\n");
@ -292,7 +292,6 @@ api_return_err(clicon_handle h,
break;
case YANG_DATA_JSON:
case YANG_PATCH_JSON:
case YANG_COLLECTION_JSON:
clicon_debug(1, "%s code:%d", __FUNCTION__, code);
if (pretty){
cprintf(cb, "{\n\"ietf-restconf:errors\" : ");

View file

@ -207,8 +207,7 @@ static const map_str2int http_media_map[] = {
{"application/yang-data+json", YANG_DATA_JSON},
{"application/yang-patch+xml", YANG_PATCH_XML},
{"application/yang-patch+json", YANG_PATCH_JSON},
{"application/yang-collection+xml", YANG_COLLECTION_XML}, /* XXX -data+xml-list?? */
{"application/yang-collection+json", YANG_COLLECTION_JSON},
{"application/yang-data+xml-list", YANG_PAGINATION_XML}, /* draft-wwlh-netconf-list-pagination-rc-02 */
{NULL, -1}
};

View file

@ -53,8 +53,7 @@ enum restconf_media{
YANG_DATA_XML, /* "application/yang-data+xml" */
YANG_PATCH_JSON, /* "application/yang-patch+json" */
YANG_PATCH_XML, /* "application/yang-patch+xml" */
YANG_COLLECTION_XML, /* draft-ietf-netconf-restconf-collection-00.txt */
YANG_COLLECTION_JSON /* draft-ietf-netconf-restconf-collection-00.txt */
YANG_PAGINATION_XML, /* draft-wwlh-netconf-list-pagination-rc-02.txt */
};
typedef enum restconf_media restconf_media;

View file

@ -191,7 +191,6 @@ int
api_data_write(clicon_handle h,
void *req,
char *api_path0,
cvec *pcvec,
int pi,
cvec *qvec,
char *data,
@ -585,7 +584,6 @@ api_data_write(clicon_handle h,
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
* @param[in] pi Offset, where to start pcvec
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] data Stream input data
@ -620,7 +618,6 @@ int
api_data_put(clicon_handle h,
void *req,
char *api_path0,
cvec *pcvec,
int pi,
cvec *qvec,
char *data,
@ -631,7 +628,7 @@ api_data_put(clicon_handle h,
restconf_media media_in;
media_in = restconf_content_type(h);
return api_data_write(h, req, api_path0, pcvec, pi, qvec, data, pretty,
return api_data_write(h, req, api_path0, pi, qvec, data, pretty,
media_in, media_out, 0, ds);
}
@ -639,8 +636,7 @@ api_data_put(clicon_handle h,
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
* @param[in] pi Offset, where to start pcvec
* @param[in] pi Offset, where to start qvec
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] data Stream input data
* @param[in] pretty Set to 1 for pretty-printed xml/json output
@ -657,7 +653,6 @@ int
api_data_patch(clicon_handle h,
void *req,
char *api_path0,
cvec *pcvec,
int pi,
cvec *qvec,
char *data,
@ -672,7 +667,7 @@ api_data_patch(clicon_handle h,
switch (media_in){
case YANG_DATA_XML:
case YANG_DATA_JSON: /* plain patch */
ret = api_data_write(h, req, api_path0, pcvec, pi, qvec, data, pretty,
ret = api_data_write(h, req, api_path0, pi, qvec, data, pretty,
media_in, media_out, 1, ds);
break;
case YANG_PATCH_JSON: /* RFC 8072 patch */

View file

@ -44,18 +44,18 @@
*/
int api_data_options(clicon_handle h, void *req);
int api_data_write(clicon_handle h, void *req, char *api_path0,
cvec *pcvec, int pi,
int pi,
cvec *qvec, char *data,
int pretty, restconf_media media_in, restconf_media media_out,
int plain_patch, ietf_ds_t ds);
int api_data_put(clicon_handle h, void *req, char *api_path,
cvec *pcvec, int pi,
int pi,
cvec *qvec, char *data,
int pretty, restconf_media media_out, ietf_ds_t ds);
int api_data_patch(clicon_handle h, void *req, char *api_path,
cvec *pcvec, int pi,
int pi,
cvec *qvec, char *data, int pretty,
restconf_media media_out, ietf_ds_t ds);

View file

@ -63,12 +63,14 @@
#include "restconf_err.h"
#include "restconf_methods_get.h"
/* Forward */
static int api_data_pagination(clicon_handle h, void *req, char *api_path, int pi, cvec *qvec, int pretty, restconf_media media_out);
/*! Generic GET (both HEAD and GET)
* According to restconf
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
* @param[in] pi Offset, where path starts
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] pretty Set to 1 for pretty-printed xml/json output
@ -90,12 +92,12 @@
* encoding is used in the response, then an error response containing a
* "400 Bad Request" status-line MUST be returned by the server.
* Netconf: <get-config>, <get>
* @note there is an ad-hoc method to determine json pagination request instead of regular GET
*/
static int
api_data_get2(clicon_handle h,
void *req,
char *api_path,
cvec *pcvec, /* XXX remove? */
int pi,
cvec *qvec,
int pretty,
@ -148,6 +150,18 @@ api_data_get2(clicon_handle h,
goto done;
goto ok;
}
/* Ad-hoc method to determine json pagination request:
* address list and one of "item/offset/.." is defined
*/
if (!head &&
(yang_keyword_get(y) == Y_LIST || yang_keyword_get(y) == Y_LEAF_LIST) &&
(cvec_find(qvec, "where") || cvec_find(qvec, "sort-by") ||
cvec_find(qvec, "direction") || cvec_find(qvec, "offset") ||
cvec_find(qvec, "limit") || cvec_find(qvec, "sublist-limit"))){
if (api_data_pagination(h, req, api_path, 0, qvec, pretty, media_out) < 0)
goto done;
goto ok;
}
}
/* Check for content attribute */
if ((attr = cvec_find_str(qvec, "content")) != NULL){
@ -305,7 +319,6 @@ api_data_get2(clicon_handle h,
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
* @param[in] pi Offset, where path starts
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] pretty Set to 1 for pretty-printed xml/json output
@ -320,10 +333,9 @@ api_data_get2(clicon_handle h,
* @see draft-ietf-netconf-restconf-collection-00.txt
*/
static int
api_data_collection(clicon_handle h,
api_data_pagination(clicon_handle h,
void *req,
char *api_path,
cvec *pcvec, /* XXX remove? */
int pi,
cvec *qvec,
int pretty,
@ -392,7 +404,7 @@ api_data_collection(clicon_handle h,
if (yang_keyword_get(y) != Y_LIST && yang_keyword_get(y) != Y_LEAF_LIST){
if (netconf_bad_element_xml(&xerr, "application",
yang_argument_get(y),
"Element is not list or leaf-list which is required for GET collection") < 0)
"Element is not list or leaf-list which is required for GET paginate") < 0)
goto done;
if ((xe = xpath_first(xerr, NULL, "rpc-error")) == NULL){
clicon_err(OE_XML, EINVAL, "rpc-error not found (internal error)");
@ -464,7 +476,7 @@ api_data_collection(clicon_handle h,
}
}
direction = cvec_find_str(qvec, "direction");
sort = cvec_find_str(qvec, "sort");
sort = cvec_find_str(qvec, "sort-by");
where = cvec_find_str(qvec, "where");
if (clicon_rpc_get_pageable_list(h, "running", xpath, nsc, content,
depth, offset, limit, direction, sort, where,
@ -492,9 +504,9 @@ api_data_collection(clicon_handle h,
goto done;
goto ok;
}
if ((xpr = xml_new("yang-collection", NULL, CX_ELMNT)) == NULL)
if ((xpr = xml_new("xml-list", NULL, CX_ELMNT)) == NULL)
goto done;
if (xmlns_set(xpr, NULL, RESTCONF_PAGINATON_NAMESPACE) < 0)
if (xmlns_set(xpr, NULL, IETF_PAGINATON_NAMESPACE) < 0)
goto done;
if (xpath_vec(xret, nsc, "%s", &xvec, &xlen, xpath) < 0)
goto done;
@ -504,30 +516,30 @@ api_data_collection(clicon_handle h,
* Here we take the latter approach to return an empty list and do not
* handle the non-exist case differently.
*/
for (i=0; i<xlen; i++){
xp = xvec[i];
ns = NULL;
if (xml2ns(xp, NULL, &ns) < 0)
goto done;
if (ns != NULL){
if (xmlns_set(xp, NULL, ns) < 0)
goto done;
}
if (xml_rm(xp) < 0)
goto done;
if (xml_insert(xpr, xp, INS_LAST, NULL, NULL) < 0)
goto done;
}
/* Normal return, no error */
if ((cbx = cbuf_new()) == NULL)
goto done;
switch (media_out){
case YANG_COLLECTION_XML:
case YANG_PAGINATION_XML:
for (i=0; i<xlen; i++){
xp = xvec[i];
ns = NULL;
if (xml2ns(xp, NULL, &ns) < 0)
goto done;
if (ns != NULL){
if (xmlns_set(xp, NULL, ns) < 0)
goto done;
}
if (xml_rm(xp) < 0)
goto done;
if (xml_insert(xpr, xp, INS_LAST, NULL, NULL) < 0)
goto done;
}
if (clicon_xml2cbuf(cbx, xpr, 0, pretty, -1) < 0) /* Dont print top object? */
goto done;
break;
case YANG_COLLECTION_JSON:
if (xml2json_cbuf(cbx, xpr, pretty) < 0)
case YANG_DATA_JSON:
if (xml2json_cbuf_vec(cbx, xvec, xlen, pretty) < 0)
goto done;
break;
default:
@ -570,7 +582,6 @@ api_data_collection(clicon_handle h,
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path According to restconf (Sec 3.5.3.1 in rfc8040)
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
* @param[in] pi Offset, where path starts
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] pretty Set to 1 for pretty-printed xml/json output
@ -586,14 +597,13 @@ int
api_data_head(clicon_handle h,
void *req,
char *api_path,
cvec *pcvec,
int pi,
cvec *qvec,
int pretty,
restconf_media media_out,
ietf_ds_t ds)
{
return api_data_get2(h, req, api_path, pcvec, pi, qvec, pretty, media_out, 1);
return api_data_get2(h, req, api_path, pi, qvec, pretty, media_out, 1);
}
/*! REST GET method
@ -625,7 +635,6 @@ int
api_data_get(clicon_handle h,
void *req,
char *api_path,
cvec *pcvec,
int pi,
cvec *qvec,
int pretty,
@ -636,15 +645,13 @@ api_data_get(clicon_handle h,
switch (media_out){
case YANG_DATA_XML:
case YANG_DATA_JSON:
if (api_data_get2(h, req, api_path, pcvec, pi, qvec, pretty, media_out, 0) < 0)
case YANG_DATA_JSON: /* ad-hoc algorithm in get to determine if a paginated request */
if (api_data_get2(h, req, api_path, pi, qvec, pretty, media_out, 0) < 0)
goto done;
break;
case YANG_COLLECTION_XML:
case YANG_COLLECTION_JSON:
if (api_data_collection(h, req, api_path, pcvec, pi, qvec, pretty, media_out) < 0)
case YANG_PAGINATION_XML:
if (api_data_pagination(h, req, api_path, pi, qvec, pretty, media_out) < 0)
goto done;
break;
default:
break;
}
@ -657,7 +664,6 @@ api_data_get(clicon_handle h,
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] path According to restconf (Sec 3.5.1.1 in [draft])
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
* @param[in] pi Offset, where path starts
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] data Stream input data

View file

@ -41,9 +41,9 @@
/*
* Prototypes
*/
int api_data_head(clicon_handle h, void *req, char *api_path, cvec *pcvec, int pi,
int api_data_head(clicon_handle h, void *req, char *api_path, int pi,
cvec *qvec, int pretty, restconf_media media_out, ietf_ds_t ds);
int api_data_get(clicon_handle h, void *req, char *api_path, cvec *pcvec, int pi,
int api_data_get(clicon_handle h, void *req, char *api_path, int pi,
cvec *qvec, int pretty, restconf_media media_out, ietf_ds_t ds);
int api_operations_get(clicon_handle h, void *req,
char *api_path, int pi, cvec *qvec, char *data,

View file

@ -188,7 +188,7 @@ yang_patch_strip_after_last_slash(char* val)
/*! YANG PATCH replace method
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] pi Offset, where to start pcvec
* @param[in] pi Offset, where to start api-path
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
@ -287,7 +287,7 @@ yang_patch_do_replace(clicon_handle h,
/*! YANG PATCH create method
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] pi Offset, where to start pcvec
* @param[in] pi Offset, where to start api-path
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
@ -343,7 +343,7 @@ yang_patch_do_create(clicon_handle h,
/*! YANG PATCH insert method
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] pi Offset, where to start pcvec
* @param[in] pi Offset, where to start api-path
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
* @param[in] ds 0 if "data" resource, 1 if rfc8527 "ds" resource
@ -431,8 +431,7 @@ yang_patch_do_insert(clicon_handle h,
/*! YANG PATCH merge method
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
* @param[in] pi Offset, where to start pcvec
* @param[in] pi Offset, where to start api-path
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
@ -447,7 +446,6 @@ yang_patch_do_insert(clicon_handle h,
static int
yang_patch_do_merge(clicon_handle h,
void *req,
cvec *pcvec,
int pi,
cvec *qvec,
int pretty,
@ -484,7 +482,7 @@ yang_patch_do_merge(clicon_handle h,
if ((json_simple_patch = yang_patch_xml2json_modified_cbuf(x_simple_patch)) == NULL)
goto done;
// Send the simple patch request
if (api_data_write(h, req, cbuf_get(simple_patch_request_uri), pcvec, pi, qvec, cbuf_get(json_simple_patch), pretty, YANG_DATA_JSON, media_out, 1, ds ) < 0)
if (api_data_write(h, req, cbuf_get(simple_patch_request_uri), pi, qvec, cbuf_get(json_simple_patch), pretty, YANG_DATA_JSON, media_out, 1, ds ) < 0)
goto done;
if (json_simple_patch){
cbuf_free(json_simple_patch);
@ -509,7 +507,6 @@ yang_patch_do_merge(clicon_handle h,
static int
yang_patch_do_value(clicon_handle h,
void *req,
cvec *pcvec,
int pi,
cvec *qvec,
int pretty,
@ -560,7 +557,7 @@ yang_patch_do_value(clicon_handle h,
goto done;
break;
case YANG_PATCH_OP_MERGE:
if (yang_patch_do_merge(h, req, pcvec, pi, qvec, pretty, media_out, ds, simple_patch_request_uri, value_vec_len, value_vec, x_simple_patch, key_xn) < 0)
if (yang_patch_do_merge(h, req, pi, qvec, pretty, media_out, ds, simple_patch_request_uri, value_vec_len, value_vec, x_simple_patch, key_xn) < 0)
goto done;
break;
default:
@ -579,8 +576,7 @@ yang_patch_do_value(clicon_handle h,
*
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
* @param[in] pi Offset, where to start pcvec
* @param[in] pi Offset, where to start api-path
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] pretty Set to 1 for pretty-printed xml/json output
* @param[in] media_out Output media
@ -591,7 +587,6 @@ yang_patch_do_value(clicon_handle h,
static int
yang_patch_do_edit(clicon_handle h,
void *req,
cvec *pcvec,
int pi,
cvec *qvec,
int pretty,
@ -693,7 +688,7 @@ yang_patch_do_edit(clicon_handle h,
// Loop through the values
for (i = 0; i < veclen; i++) {
if (yang_patch_do_value(h, req, pcvec, pi, qvec, pretty, media_out, ds,
if (yang_patch_do_value(h, req, pi, qvec, pretty, media_out, ds,
vec[i], modname,
operation, where_val, point_val, simple_patch_request_uri, target_val,
api_path, key_xn) < 0)
@ -729,8 +724,7 @@ yang_patch_do_edit(clicon_handle h,
* @param[in] h Clixon handle
* @param[in] req Generic Www handle
* @param[in] api_path0 According to restconf (Sec 3.5.3.1 in rfc8040)
* @param[in] pcvec Vector of path ie DOCUMENT_URI element
* @param[in] pi Offset, where to start pcvec
* @param[in] pi Offset, where to start api-path
* @param[in] qvec Vector of query string (QUERY_STRING)
* @param[in] data Stream input data
* @param[in] pretty Set to 1 for pretty-printed xml/json output
@ -749,7 +743,6 @@ int
api_data_yang_patch(clicon_handle h,
void *req,
char *api_path0,
cvec *pcvec,
int pi,
cvec *qvec,
char *data,
@ -828,7 +821,7 @@ api_data_yang_patch(clicon_handle h,
if (xpath_vec(xpatch, NULL, "yang-patch/edit", &vec, &veclen) < 0)
goto done;
for (i = 0; i < veclen; i++) {
if (yang_patch_do_edit(h, req, pcvec, pi, qvec, pretty, media_out, ds,
if (yang_patch_do_edit(h, req, pi, qvec, pretty, media_out, ds,
yspec,
vec[i],
uripath0, api_path) < 0)
@ -854,7 +847,6 @@ int
api_data_yang_patch(clicon_handle h,
void *req,
char *api_path0,
cvec *pcvec,
int pi,
cvec *qvec,
char *data,

View file

@ -44,7 +44,7 @@
* Prototypes
*/
int api_data_yang_patch(clicon_handle h, void *req, char *api_path0,
cvec *pcvec, int pi,
int pi,
cvec *qvec, char *data,
int pretty, restconf_media media_in, restconf_media media_out,
ietf_ds_t ds);

View file

@ -329,10 +329,10 @@ api_data(clicon_handle h,
if (dynamic)
retval = restconf_method_notallowed(h, req, "GET,POST", pretty, media_out);
else
retval = api_data_head(h, req, api_path, pcvec, pi, qvec, pretty, media_out, ds);
retval = api_data_head(h, req, api_path, pi, qvec, pretty, media_out, ds);
}
else if (strcmp(request_method, "GET")==0) {
retval = api_data_get(h, req, api_path, pcvec, pi, qvec, pretty, media_out, ds);
retval = api_data_get(h, req, api_path, pi, qvec, pretty, media_out, ds);
}
else if (strcmp(request_method, "POST")==0) {
retval = api_data_post(h, req, api_path, pi, qvec, data, pretty, restconf_content_type(h), media_out, ds);
@ -341,13 +341,13 @@ api_data(clicon_handle h,
if (read_only)
retval = restconf_method_notallowed(h, req, "GET,POST", pretty, media_out);
else
retval = api_data_put(h, req, api_path, pcvec, pi, qvec, data, pretty, media_out, ds);
retval = api_data_put(h, req, api_path, pi, qvec, data, pretty, media_out, ds);
}
else if (strcmp(request_method, "PATCH")==0) {
if (read_only) {
retval = restconf_method_notallowed(h, req, "GET,POST", pretty, media_out);
}
retval = api_data_patch(h, req, api_path, pcvec, pi, qvec, data, pretty, media_out, ds);
retval = api_data_patch(h, req, api_path, pi, qvec, data, pretty, media_out, ds);
}
else if (strcmp(request_method, "DELETE")==0) {
if (read_only)