mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-20 21:53:12 +00:00
152 lines
4.6 KiB
C
152 lines
4.6 KiB
C
/*
|
|
Serval DNA HTTP RESTful interface
|
|
Copyright (C) 2013,2014 Serval Project Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "serval.h"
|
|
#include "conf.h"
|
|
#include "httpd.h"
|
|
#include "server.h"
|
|
#include "keyring.h"
|
|
#include "strbuf_helpers.h"
|
|
|
|
extern keyring_file *keyring;
|
|
|
|
#define keyring_TOKEN_STRLEN (BASE64_ENCODED_LEN(sizeof(rhizome_bid_t) + sizeof(uint64_t)))
|
|
#define alloca_keyring_token(bid, offset) keyring_ token_to_str(alloca(keyring_TOKEN_STRLEN + 1), (bid), (offset))
|
|
|
|
static HTTP_HANDLER restful_keyring_identitylist_json;
|
|
|
|
int restful_keyring_(httpd_request *r, const char *remainder)
|
|
{
|
|
r->http.response.header.content_type = CONTENT_TYPE_JSON;
|
|
if (!is_rhizome_http_enabled())
|
|
return 403;
|
|
int ret = authorize_restful(&r->http);
|
|
if (ret)
|
|
return ret;
|
|
const char *verb = HTTP_VERB_GET;
|
|
http_size_t content_length = CONTENT_LENGTH_UNKNOWN;
|
|
HTTP_HANDLER *handler = NULL;
|
|
|
|
if (strcmp(remainder, "identities.json") == 0) {
|
|
handler = restful_keyring_identitylist_json;
|
|
verb = HTTP_VERB_GET;
|
|
remainder = "";
|
|
}
|
|
|
|
if (handler == NULL)
|
|
return 404;
|
|
if ( content_length != CONTENT_LENGTH_UNKNOWN
|
|
&& r->http.request_header.content_length != CONTENT_LENGTH_UNKNOWN
|
|
&& r->http.request_header.content_length != content_length) {
|
|
http_request_simple_response(&r->http, 400, "Bad content length");
|
|
return 400;
|
|
}
|
|
if (r->http.verb != verb)
|
|
return 405;
|
|
return handler(r, remainder);
|
|
}
|
|
|
|
static HTTP_CONTENT_GENERATOR restful_keyring_identitylist_json_content;
|
|
|
|
static int restful_keyring_identitylist_json(httpd_request *r, const char *remainder)
|
|
{
|
|
if (*remainder)
|
|
return 404;
|
|
|
|
r->u.sidlist.phase = LIST_HEADER;
|
|
keyring_iterator_start(keyring, &r->u.sidlist.it);
|
|
|
|
http_request_response_generated(&r->http, 200, CONTENT_TYPE_JSON, restful_keyring_identitylist_json_content);
|
|
return 1;
|
|
}
|
|
|
|
static HTTP_CONTENT_GENERATOR_STRBUF_CHUNKER restful_keyring_identitylist_json_content_chunk;
|
|
|
|
static int restful_keyring_identitylist_json_content(struct http_request *hr, unsigned char *buf, size_t bufsz, struct http_content_generator_result *result)
|
|
{
|
|
return generate_http_content_from_strbuf_chunks(hr, (char *)buf, bufsz, result, restful_keyring_identitylist_json_content_chunk);
|
|
}
|
|
|
|
static int restful_keyring_identitylist_json_content_chunk(struct http_request *hr, strbuf b)
|
|
{
|
|
httpd_request *r = (httpd_request *) hr;
|
|
// The "my_sid" and "their_sid" per-conversation fields allow the same JSON structure to be used
|
|
// in a future, non-SID-specific request, eg, to list all conversations for all currently open
|
|
// identities.
|
|
const char *headers[] = {
|
|
"sid",
|
|
"did",
|
|
"name"
|
|
};
|
|
switch (r->u.sidlist.phase) {
|
|
case LIST_HEADER:
|
|
strbuf_puts(b, "{\n\"header\":[");
|
|
unsigned i;
|
|
for (i = 0; i != NELS(headers); ++i) {
|
|
if (i)
|
|
strbuf_putc(b, ',');
|
|
strbuf_json_string(b, headers[i]);
|
|
}
|
|
strbuf_puts(b, "],\n\"rows\":[");
|
|
if (!strbuf_overrun(b)){
|
|
r->u.sidlist.phase = LIST_FIRST;
|
|
if (!keyring_next_identity(&r->u.sidlist.it))
|
|
r->u.sidlist.phase = LIST_END;
|
|
}
|
|
return 1;
|
|
|
|
case LIST_ROWS:
|
|
strbuf_putc(b, ',');
|
|
case LIST_FIRST:
|
|
r->u.sidlist.phase = LIST_ROWS;
|
|
const sid_t *sidp = NULL;
|
|
const char *did = NULL;
|
|
const char *name = NULL;
|
|
keyring_identity_extract(r->u.sidlist.it.identity, &sidp, &did, &name);
|
|
if (sidp || did) {
|
|
strbuf_puts(b, "\n[");
|
|
strbuf_json_string(b, alloca_tohex_sid_t(*sidp));
|
|
strbuf_puts(b, ",");
|
|
strbuf_json_string(b, did);
|
|
strbuf_puts(b, ",");
|
|
strbuf_json_string(b, name);
|
|
strbuf_puts(b, "]");
|
|
}
|
|
|
|
if (!strbuf_overrun(b)) {
|
|
if (!keyring_next_identity(&r->u.sidlist.it))
|
|
r->u.sidlist.phase = LIST_END;
|
|
}
|
|
return 1;
|
|
|
|
case LIST_END:
|
|
strbuf_puts(b, "\n]\n}\n");
|
|
if (strbuf_overrun(b))
|
|
return 1;
|
|
|
|
r->u.sidlist.phase = LIST_DONE;
|
|
// fall through...
|
|
case LIST_DONE:
|
|
return 0;
|
|
}
|
|
abort();
|
|
return 0;
|
|
}
|
|
|