Implement HTTP POST /restful/meshms/<SID>/<SID>/sendmessage

Rename struct meshms_ply fields from "buffer" to "record" for
consistency with comment terminology
This commit is contained in:
Andrew Bettison 2014-02-05 14:28:15 +10:30
parent fb2709d10c
commit fd86a3d17f
9 changed files with 340 additions and 128 deletions

77
httpd.c
View File

@ -350,6 +350,83 @@ int authorize(struct http_request *r)
return 0;
}
int accumulate_text(httpd_request *r, const char *partname, char *textbuf, size_t textsiz, size_t *textlenp, const char *buf, size_t len)
{
if (len) {
size_t newlen = *textlenp + len;
if (newlen > textsiz) {
if (config.debug.httpd)
DEBUGF("Form part \"%s\" too long, %zu bytes overflows maximum %zu by %zu",
partname, newlen, textsiz, (size_t)(newlen - textsiz)
);
strbuf msg = strbuf_alloca(100);
strbuf_sprintf(msg, "Overflow in \"%s\" form part", partname);
http_request_simple_response(&r->http, 403, strbuf_str(msg));
return 0;
}
memcpy(textbuf + *textlenp, buf, len);
*textlenp = newlen;
}
return 1;
}
int form_buf_malloc_init(struct form_buf_malloc *f, size_t size_limit)
{
assert(f->buffer == NULL);
assert(f->buffer_alloc_size == 0);
assert(f->length == 0);
f->size_limit = size_limit;
return 0;
}
int form_buf_malloc_accumulate(httpd_request *r, const char *partname, struct form_buf_malloc *f, const char *buf, size_t len)
{
if (len == 0)
return 0;
size_t newlen = f->length + len;
if (newlen > f->size_limit) {
if (config.debug.httpd)
DEBUGF("form part \"%s\" overflow, %zu bytes exceeds limit %zu by %zu",
partname, newlen, f->size_limit, (size_t)(newlen - f->size_limit)
);
strbuf msg = strbuf_alloca(100);
strbuf_sprintf(msg, "Overflow in \"%s\" form part", partname);
http_request_simple_response(&r->http, 403, strbuf_str(msg));
return 403;
}
if (newlen > f->buffer_alloc_size) {
if ((f->buffer = erealloc(f->buffer, newlen)) == NULL) {
http_request_simple_response(&r->http, 500, NULL);
return 500;
}
f->buffer_alloc_size = newlen;
}
memcpy(f->buffer + f->length, buf, len);
f->length = newlen;
return 0;
}
void form_buf_malloc_release(struct form_buf_malloc *f)
{
if (f->buffer) {
free(f->buffer);
f->buffer = NULL;
}
f->buffer_alloc_size = 0;
f->length = 0;
f->size_limit = 0;
}
int http_response_form_part(httpd_request *r, const char *what, const char *partname, const char *text, size_t textlen)
{
if (config.debug.httpd)
DEBUGF("%s \"%s\" form part %s", what, partname, text ? alloca_toprint(-1, text, textlen) : "");
strbuf msg = strbuf_alloca(100);
strbuf_sprintf(msg, "%s \"%s\" form part", what, partname);
http_request_simple_response(&r->http, 403, strbuf_str(msg));
return 403;
}
static int root_page(httpd_request *r, const char *remainder)
{
if (*remainder)

32
httpd.h
View File

@ -34,6 +34,19 @@ extern unsigned int httpd_request_count;
enum list_phase { LIST_HEADER = 0, LIST_ROWS, LIST_END, LIST_DONE };
struct form_buf_malloc {
char *buffer;
size_t size_limit; // == 0 means no limit
size_t buffer_alloc_size;
size_t length;
};
struct httpd_request;
int form_buf_malloc_init(struct form_buf_malloc *, size_t size_limit);
int form_buf_malloc_accumulate(struct httpd_request *, const char *partname, struct form_buf_malloc *, const char *, size_t);
void form_buf_malloc_release(struct form_buf_malloc *);
typedef struct httpd_request
{
struct http_request http; // MUST BE FIRST ELEMENT
@ -108,9 +121,7 @@ typedef struct httpd_request
size_t force_new_text_len;
bool_t force_new;
// For storing the manifest text (malloc/realloc) as we receive it
char *manifest_text;
size_t manifest_text_size;
size_t manifest_len;
struct form_buf_malloc manifest;
// For receiving the payload
enum rhizome_payload_status payload_status;
uint64_t payload_size;
@ -159,6 +170,18 @@ typedef struct httpd_request
}
msglist;
/* For responses that send a MeshMS message.
*/
struct {
// Which part is currently being received
const char *current_part;
// Which parts have already been received
bool_t received_message;
// The text of the message to send
struct form_buf_malloc message;
}
sendmsg;
} u;
} httpd_request;
@ -169,6 +192,9 @@ typedef int HTTP_HANDLER(httpd_request *r, const char *remainder);
int is_http_header_complete(const char *buf, size_t len, size_t read_since_last_call);
int authorize(struct http_request *r);
int http_response_form_part(httpd_request *r, const char *what, const char *partname, const char *text, size_t textlen);
int accumulate_text(httpd_request *r, const char *partname, char *textbuf, size_t textsiz, size_t *textlenp, const char *buf, size_t len);
int rhizome_response_content_init_filehash(httpd_request *r, const rhizome_filehash_t *hash);
int rhizome_response_content_init_payload(httpd_request *r, rhizome_manifest *);
HTTP_CONTENT_GENERATOR rhizome_payload_content;

View File

@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "dataformats.h"
#define MESHMS_BLOCK_TYPE_ACK 0x01
#define MESHMS_BLOCK_TYPE_MESSAGE 0x02
#define MESHMS_BLOCK_TYPE_MESSAGE 0x02 // NUL-terminated UTF8 string
#define MESHMS_BLOCK_TYPE_BID_REFERENCE 0x03
void meshms_free_conversations(struct meshms_conversations *conv)
@ -206,10 +206,11 @@ static int create_ply(const sid_t *my_sid, struct meshms_conversations *conv, rh
return 0;
}
static int append_footer(unsigned char *buffer, char type, int payload_len)
static int append_footer(unsigned char *buffer, char type, size_t message_len)
{
payload_len = (payload_len << 4) | (type&0xF);
write_uint16(buffer, payload_len);
assert(message_len <= MESHMS_MESSAGE_MAX_LEN);
message_len = (message_len << 4) | (type&0xF);
write_uint16(buffer, message_len);
return 2;
}
@ -231,11 +232,11 @@ static int ply_read_open(struct meshms_ply_read *ply, const rhizome_bid_t *bid,
static void ply_read_close(struct meshms_ply_read *ply)
{
if (ply->buffer){
free(ply->buffer);
ply->buffer=NULL;
if (ply->record){
free(ply->record);
ply->record=NULL;
}
ply->buffer_size=0;
ply->record_size=0;
ply->buff.len=0;
rhizome_read_close(&ply->read);
}
@ -248,7 +249,7 @@ static int ply_read_prev(struct meshms_ply_read *ply)
unsigned char footer[2];
if (ply->read.offset <= sizeof footer) {
if (config.debug.meshms)
DEBUGF("EOF");
DEBUG("EOF");
return 1;
}
ply->read.offset -= sizeof footer;
@ -271,14 +272,14 @@ static int ply_read_prev(struct meshms_ply_read *ply)
}
ply->read.offset -= ply->record_length + sizeof(footer);
uint64_t record_start = ply->read.offset;
if (ply->buffer_size < ply->record_length){
ply->buffer_size = ply->record_length;
unsigned char *b=realloc(ply->buffer, ply->buffer_size);
if (ply->record_size < ply->record_length){
ply->record_size = ply->record_length;
unsigned char *b = erealloc(ply->record, ply->record_size);
if (!b)
return WHY("realloc() failed");
ply->buffer = b;
return -1;
ply->record = b;
}
read = rhizome_read_buffered(&ply->read, &ply->buff, ply->buffer, ply->record_length);
read = rhizome_read_buffered(&ply->read, &ply->buff, ply->record, ply->record_length);
if (read == -1)
return WHYF("rhizome_read_buffered() failed");
if ((size_t) read != ply->record_length)
@ -416,7 +417,7 @@ static int update_conversation(const sid_t *my_sid, struct meshms_conversations
goto end;
if (ret==0){
if (unpack_uint(ply.buffer, ply.record_length, &previous_ack) == -1)
if (unpack_uint(ply.record, ply.record_length, &previous_ack) == -1)
previous_ack=0;
}
if (config.debug.meshms)
@ -740,7 +741,7 @@ int meshms_message_iterator_open(struct meshms_message_iterator *iter, const sid
// Find their latest ACK so we know which of my messages have been delivered.
int r = ply_find_prev(&iter->_their_reader, MESHMS_BLOCK_TYPE_ACK);
if (r == 0) {
if (unpack_uint(iter->_their_reader.buffer, iter->_their_reader.record_length, &iter->latest_ack_my_offset) == -1)
if (unpack_uint(iter->_their_reader.record, iter->_their_reader.record_length, &iter->latest_ack_my_offset) == -1)
iter->latest_ack_my_offset = 0;
else
iter->latest_ack_offset = iter->_their_reader.record_end_offset;
@ -804,15 +805,23 @@ int meshms_message_iterator_prev(struct meshms_message_iterator *iter)
iter->type = ACK_RECEIVED;
iter->offset = iter->_their_reader.record_end_offset;
iter->text = NULL;
if (unpack_uint(iter->_their_reader.buffer, iter->_their_reader.record_length, &iter->ack_offset) == -1)
iter->text_length = 0;
if (unpack_uint(iter->_their_reader.record, iter->_their_reader.record_length, &iter->ack_offset) == -1)
iter->ack_offset = 0;
return 0;
case MESHMS_BLOCK_TYPE_MESSAGE:
iter->type = MESSAGE_RECEIVED;
iter->offset = iter->_their_reader.record_end_offset;
iter->text = (const char *)iter->_their_reader.buffer;
iter->read = iter->_their_reader.record_end_offset <= iter->_conv->read_offset;
return 0;
iter->text = (const char *)iter->_their_reader.record;
iter->text_length = iter->_their_reader.record_length;
if ( iter->_their_reader.record_length != 0
&& iter->_their_reader.record[iter->_their_reader.record_length - 1] == '\0'
) {
iter->read = iter->_their_reader.record_end_offset <= iter->_conv->read_offset;
return 0;
}
WARN("Malformed MeshMS2 ply journal, missing NUL terminator");
break;
}
continue;
}
@ -827,11 +836,11 @@ int meshms_message_iterator_prev(struct meshms_message_iterator *iter)
case MESHMS_BLOCK_TYPE_ACK:
// Read the received messages up to the ack'ed offset
if (iter->_conv->found_their_ply) {
int ofs = unpack_uint(iter->_my_reader.buffer, iter->_my_reader.record_length, (uint64_t*)&iter->_their_reader.read.offset);
int ofs = unpack_uint(iter->_my_reader.record, iter->_my_reader.record_length, (uint64_t*)&iter->_their_reader.read.offset);
if (ofs == -1)
return WHYF("Malformed ACK");
uint64_t end_range;
int x = unpack_uint(iter->_my_reader.buffer + ofs, iter->_my_reader.record_length - ofs, &end_range);
int x = unpack_uint(iter->_my_reader.record + ofs, iter->_my_reader.record_length - ofs, &end_range);
if (x == -1)
iter->_end_range = 0;
else
@ -846,7 +855,8 @@ int meshms_message_iterator_prev(struct meshms_message_iterator *iter)
case MESHMS_BLOCK_TYPE_MESSAGE:
iter->type = MESSAGE_SENT;
iter->offset = iter->_my_reader.record_end_offset;
iter->text = (const char *)iter->_my_reader.buffer;
iter->text = (const char *)iter->_my_reader.record;
iter->text_length = iter->_my_reader.record_length;
iter->delivered = iter->latest_ack_my_offset && iter->_my_reader.record_end_offset <= iter->latest_ack_my_offset;
return 0;
}
@ -855,6 +865,27 @@ int meshms_message_iterator_prev(struct meshms_message_iterator *iter)
return ret;
}
int meshms_send_message(const sid_t *sender, const sid_t *recipient, const char *message, size_t message_len)
{
assert(message_len != 0);
if (message_len > MESHMS_MESSAGE_MAX_LEN)
return WHY("message too long");
struct meshms_conversations *conv = find_or_create_conv(sender, recipient);
if (!conv)
return -1;
// construct a message payload
// TODO, new format here.
unsigned char buffer[message_len + 4];
strncpy((char*)buffer, message, message_len);
// ensure message is NUL terminated
if (message[message_len - 1] != '\0')
buffer[message_len++] = '\0';
message_len += append_footer(buffer + message_len, MESHMS_BLOCK_TYPE_MESSAGE, message_len);
int ret = append_meshms_buffer(sender, conv, buffer, message_len);
meshms_free_conversations(conv);
return ret;
}
// output the list of existing conversations for a given local identity
int app_meshms_conversations(const struct cli_parsed *parsed, struct cli_context *context)
{
@ -934,21 +965,8 @@ int app_meshms_send_message(const struct cli_parsed *parsed, struct cli_context
return WHY("invalid sender SID");
if (str_to_sid_t(&their_sid, their_sidhex) == -1)
return WHY("invalid recipient SID");
struct meshms_conversations *conv = find_or_create_conv(&my_sid, &their_sid);
if (!conv) {
keyring_free(keyring);
return -1;
}
// construct a message payload
int message_len = strlen(message)+1;
// TODO, new format here.
unsigned char buffer[message_len+3];
strcpy((char*)buffer, message); // message
message_len+=append_footer(buffer+message_len, MESHMS_BLOCK_TYPE_MESSAGE, message_len);
int ret = append_meshms_buffer(&my_sid, conv, buffer, message_len);
meshms_free_conversations(conv);
// include terminating NUL
int ret = meshms_send_message(&my_sid, &their_sid, message, strlen(message) + 1);
keyring_free(keyring);
return ret;
}

View File

@ -23,6 +23,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "rhizome.h"
#define MESHMS_MESSAGE_MAX_LEN 4095
// the manifest details for one half of a conversation
struct meshms_ply {
rhizome_bid_t bundle_id;
@ -65,10 +67,10 @@ struct meshms_ply_read {
// details of the current record
uint64_t record_end_offset;
uint16_t record_length;
size_t buffer_size;
size_t record_size;
char type;
// raw record data
unsigned char *buffer;
unsigned char *record;
};
/* Fetch the list of all MeshMS conversations into a binary tree whose nodes
@ -124,7 +126,8 @@ struct meshms_message_iterator {
// (mine). For MESSAGE_RECEIVED and ACK_RECEIVED, it is the byte position
// within the remote ply (theirs).
uint64_t offset;
const char *text; // NUL terminated text of message
const char *text; // text of UTF8 message (NUL terminated)
size_t text_length; // excluding terminating NUL
union {
bool_t delivered; // for MESSAGE_SENT
bool_t read; // for MESSAGE_RECEIVED
@ -145,4 +148,11 @@ int meshms_message_iterator_is_open(const struct meshms_message_iterator *);
void meshms_message_iterator_close(struct meshms_message_iterator *);
int meshms_message_iterator_prev(struct meshms_message_iterator *);
/* Append a message ('message_len' bytes of UTF8 at 'message') to the sender's
* ply in the conversation between 'sender' and 'recipient'. If no
* conversation (ply bundle) exists, then create it. Returns 0 on success, -1
* on error (already logged).
*/
int meshms_send_message(const sid_t *sender, const sid_t *recipient, const char *message, size_t message_len);
#endif // __SERVAL_DNA__MESHMS_H

View File

@ -33,6 +33,11 @@ static void finalise_union_meshms_messagelist(httpd_request *r)
meshms_message_iterator_close(&r->u.msglist.iter);
}
static void finalise_union_meshms_sendmessage(httpd_request *r)
{
form_buf_malloc_release(&r->u.sendmsg.message);
}
#define MESHMS_TOKEN_STRLEN (BASE64_ENCODED_LEN(sizeof(rhizome_bid_t) + sizeof(uint64_t)))
#define alloca_meshms_token(bid, offset) meshms_token_to_str(alloca(MESHMS_TOKEN_STRLEN + 1), (bid), (offset))
@ -62,12 +67,14 @@ static int strn_to_meshms_token(const char *str, rhizome_bid_t *bidp, uint64_t *
static HTTP_HANDLER restful_meshms_conversationlist_json;
static HTTP_HANDLER restful_meshms_messagelist_json;
static HTTP_HANDLER restful_meshms_newsince_messagelist_json;
static HTTP_HANDLER restful_meshms_sendmessage;
int restful_meshms_(httpd_request *r, const char *remainder)
{
r->http.response.header.content_type = "application/json";
if (!is_rhizome_http_enabled())
return 403;
const char *verb = HTTP_VERB_GET;
HTTP_HANDLER *handler = NULL;
const char *end;
if (strn_to_sid_t(&r->sid1, remainder, &end) != -1) {
@ -88,11 +95,16 @@ int restful_meshms_(httpd_request *r, const char *remainder)
handler = restful_meshms_newsince_messagelist_json;
remainder = "";
}
else if (strcmp(remainder, "/sendmessage") == 0) {
handler = restful_meshms_sendmessage;
verb = HTTP_VERB_POST;
remainder = "";
}
}
}
if (handler == NULL)
return 404;
if (r->http.verb != HTTP_VERB_GET)
if (r->http.verb != verb)
return 405;
int ret = authorize(&r->http);
if (ret)
@ -407,3 +419,88 @@ static int restful_meshms_messagelist_json_content_chunk(struct http_request *hr
return 0;
}
static HTTP_REQUEST_PARSER restful_meshms_sendmessage_end;
static int send_mime_part_start(struct http_request *);
static int send_mime_part_end(struct http_request *);
static int send_mime_part_header(struct http_request *, const struct mime_part_headers *);
static int send_mime_part_body(struct http_request *, char *, size_t);
static int restful_meshms_sendmessage(httpd_request *r, const char *remainder)
{
if (*remainder)
return 404;
assert(r->finalise_union == NULL);
r->finalise_union = finalise_union_meshms_sendmessage;
// Parse the request body as multipart/form-data.
assert(r->u.sendmsg.current_part == NULL);
assert(!r->u.sendmsg.received_message);
r->http.form_data.handle_mime_part_start = send_mime_part_start;
r->http.form_data.handle_mime_part_end = send_mime_part_end;
r->http.form_data.handle_mime_part_header = send_mime_part_header;
r->http.form_data.handle_mime_body = send_mime_part_body;
// Send the message once the body has arrived.
r->http.handle_content_end = restful_meshms_sendmessage_end;
return 1;
}
static char PART_MESSAGE[] = "message";
static int send_mime_part_start(struct http_request *hr)
{
httpd_request *r = (httpd_request *) hr;
assert(r->u.sendmsg.current_part == NULL);
return 0;
}
static int send_mime_part_end(struct http_request *hr)
{
httpd_request *r = (httpd_request *) hr;
if (r->u.sendmsg.current_part == PART_MESSAGE) {
if (r->u.sendmsg.message.length == 0)
return http_response_form_part(r, "Invalid (empty)", PART_MESSAGE, NULL, 0);
r->u.sendmsg.received_message = 1;
if (config.debug.httpd)
DEBUGF("received %s = %s", PART_MESSAGE, alloca_toprint(-1, r->u.sendmsg.message.buffer, r->u.sendmsg.message.length));
} else
FATALF("current_part = %s", alloca_str_toprint(r->u.sendmsg.current_part));
r->u.sendmsg.current_part = NULL;
return 0;
}
static int send_mime_part_header(struct http_request *hr, const struct mime_part_headers *h)
{
httpd_request *r = (httpd_request *) hr;
if (strcmp(h->content_disposition.name, PART_MESSAGE) == 0) {
if (r->u.sendmsg.received_message)
return http_response_form_part(r, "Duplicate", PART_MESSAGE, NULL, 0);
r->u.sendmsg.current_part = PART_MESSAGE;
form_buf_malloc_init(&r->u.sendmsg.message, MESHMS_MESSAGE_MAX_LEN);
}
else
return http_response_form_part(r, "Unsupported", h->content_disposition.name, NULL, 0);
return 0;
}
static int send_mime_part_body(struct http_request *hr, char *buf, size_t len)
{
httpd_request *r = (httpd_request *) hr;
if (r->u.sendmsg.current_part == PART_MESSAGE) {
form_buf_malloc_accumulate(r, PART_MESSAGE, &r->u.sendmsg.message, buf, len);
} else
FATALF("current_part = %s", alloca_str_toprint(r->u.sendmsg.current_part));
return 0;
}
static int restful_meshms_sendmessage_end(struct http_request *hr)
{
httpd_request *r = (httpd_request *) hr;
if (!r->u.sendmsg.received_message)
return http_response_form_part(r, "Missing", PART_MESSAGE, NULL, 0);
assert(r->u.sendmsg.message.length > 0);
assert(r->u.sendmsg.message.length <= MESHMS_MESSAGE_MAX_LEN);
int ret = meshms_send_message(&r->sid1, &r->sid2, r->u.sendmsg.message.buffer, r->u.sendmsg.message.length);
if (ret == -1)
return 500;
http_request_simple_response(&r->http, 201, "Message sent");
return 201;
}

View File

@ -31,10 +31,7 @@ static void finalise_union_read_state(httpd_request *r)
static void finalise_union_rhizome_insert(httpd_request *r)
{
if (r->u.insert.manifest_text) {
free(r->u.insert.manifest_text);
r->u.insert.manifest_text = NULL;
}
form_buf_malloc_release(&r->u.insert.manifest);
if (r->u.insert.write.blob_fd != -1)
rhizome_fail_write(&r->u.insert.write);
}
@ -284,26 +281,16 @@ static int insert_mime_part_start(struct http_request *hr)
return 0;
}
static int http_response_form_part(httpd_request *r, const char *what, const char *partname, const char *text, size_t textlen)
{
if (config.debug.rhizome)
DEBUGF("%s \"%s\" form part %s", what, partname, text ? alloca_toprint(-1, text, textlen) : "");
strbuf msg = strbuf_alloca(100);
strbuf_sprintf(msg, "%s \"%s\" form part", what, partname);
http_request_simple_response(&r->http, 403, strbuf_str(msg));
return 403;
}
static int insert_make_manifest(httpd_request *r)
{
if (!r->u.insert.received_manifest)
return http_response_form_part(r, "Missing", PART_MANIFEST, NULL, 0);
if ((r->manifest = rhizome_new_manifest())) {
if (r->u.insert.manifest_len == 0)
if (r->u.insert.manifest.length == 0)
return 0;
assert(r->u.insert.manifest_len <= sizeof r->manifest->manifestdata);
memcpy(r->manifest->manifestdata, r->u.insert.manifest_text, r->u.insert.manifest_len);
r->manifest->manifest_all_bytes = r->u.insert.manifest_len;
assert(r->u.insert.manifest.length <= sizeof r->manifest->manifestdata);
memcpy(r->manifest->manifestdata, r->u.insert.manifest.buffer, r->u.insert.manifest.length);
r->manifest->manifest_all_bytes = r->u.insert.manifest.length;
int n = rhizome_manifest_parse(r->manifest);
switch (n) {
case -1:
@ -330,19 +317,19 @@ static int insert_mime_part_header(struct http_request *hr, const struct mime_pa
if (r->u.insert.received_author)
return http_response_form_part(r, "Duplicate", PART_AUTHOR, NULL, 0);
r->u.insert.current_part = PART_AUTHOR;
assert(r->u.insert.author_hex_len == 0);
}
else if (strcmp(h->content_disposition.name, PART_SECRET) == 0) {
if (r->u.insert.received_secret)
return http_response_form_part(r, "Duplicate", PART_SECRET, NULL, 0);
r->u.insert.current_part = PART_SECRET;
assert(r->u.insert.secret_hex_len == 0);
}
else if (strcmp(h->content_disposition.name, PART_MANIFEST) == 0) {
// Reject a request if it has a repeated manifest part.
if (r->u.insert.received_manifest)
return http_response_form_part(r, "Duplicate", PART_MANIFEST, NULL, 0);
assert(r->u.insert.manifest_text == NULL);
assert(r->u.insert.manifest_text_size == 0);
assert(r->u.insert.manifest_len == 0);
form_buf_malloc_init(&r->u.insert.manifest, MAX_MANIFEST_BYTES);
if ( strcmp(h->content_type.type, "rhizome-manifest") != 0
|| strcmp(h->content_type.subtype, "text") != 0
)
@ -384,26 +371,6 @@ static int insert_mime_part_header(struct http_request *hr, const struct mime_pa
return 0;
}
static int accumulate_text(httpd_request *r, const char *partname, char *textbuf, size_t textsiz, size_t *textlenp, const char *buf, size_t len)
{
if (len) {
size_t newlen = *textlenp + len;
if (newlen > textsiz) {
if (config.debug.rhizome)
DEBUGF("Form part \"%s\" too long, %zu bytes overflows maximum %zu by %zu",
partname, newlen, textsiz, (size_t)(newlen - textsiz)
);
strbuf msg = strbuf_alloca(100);
strbuf_sprintf(msg, "Overflow in \"%s\" form part", partname);
http_request_simple_response(&r->http, 403, strbuf_str(msg));
return 0;
}
memcpy(textbuf + *textlenp, buf, len);
*textlenp = newlen;
}
return 1;
}
static int insert_mime_part_body(struct http_request *hr, char *buf, size_t len)
{
httpd_request *r = (httpd_request *) hr;
@ -422,24 +389,7 @@ static int insert_mime_part_body(struct http_request *hr, char *buf, size_t len)
buf, len);
}
else if (r->u.insert.current_part == PART_MANIFEST) {
if (len == 0)
return 0;
size_t newlen = r->u.insert.manifest_len + len;
if (newlen > MAX_MANIFEST_BYTES) {
if (config.debug.rhizome)
DEBUGF("manifest too large, %zu bytes overflows maximum %zu by %zu",
newlen, (size_t)MAX_MANIFEST_BYTES, (size_t)(newlen - MAX_MANIFEST_BYTES)
);
http_request_simple_response(&r->http, 403, "Manifest size overflow");
return 403;
}
if (newlen > r->u.insert.manifest_text_size) {
if ((r->u.insert.manifest_text = erealloc(r->u.insert.manifest_text, newlen)) == NULL)
return 500;
r->u.insert.manifest_text_size = newlen;
}
memcpy(r->u.insert.manifest_text + r->u.insert.manifest_len, buf, len);
r->u.insert.manifest_len = newlen;
form_buf_malloc_accumulate(r, PART_MANIFEST, &r->u.insert.manifest, buf, len);
}
else if (r->u.insert.current_part == PART_PAYLOAD) {
r->u.insert.payload_size += len;

View File

@ -471,36 +471,49 @@ strbuf strbuf_json_boolean(strbuf sb, int boolean)
return sb;
}
static void _json_char(strbuf sb, char c)
{
if (c == '"' || c == '\\') {
strbuf_putc(sb, '\\');
strbuf_putc(sb, c);
}
else if (c == '\b')
strbuf_puts(sb, "\\b");
else if (c == '\f')
strbuf_puts(sb, "\\f");
else if (c == '\n')
strbuf_puts(sb, "\\n");
else if (c == '\r')
strbuf_puts(sb, "\\r");
else if (c == '\t')
strbuf_puts(sb, "\\t");
else if (iscntrl(c))
strbuf_sprintf(sb, "\\u%04X", (unsigned char) c);
else
strbuf_putc(sb, c);
}
strbuf strbuf_json_string(strbuf sb, const char *str)
{
if (str) {
strbuf_putc(sb, '"');
for (; *str; ++str) {
if (*str == '"' || *str == '\\') {
strbuf_putc(sb, '\\');
strbuf_putc(sb, *str);
}
else if (*str == '\b')
strbuf_puts(sb, "\\b");
else if (*str == '\f')
strbuf_puts(sb, "\\f");
else if (*str == '\n')
strbuf_puts(sb, "\\n");
else if (*str == '\r')
strbuf_puts(sb, "\\r");
else if (*str == '\t')
strbuf_puts(sb, "\\t");
else if (iscntrl(*str))
strbuf_sprintf(sb, "\\u%04X", (unsigned char) *str);
else
strbuf_putc(sb, *str);
}
for (; *str; ++str)
_json_char(sb, *str);
strbuf_putc(sb, '"');
} else
strbuf_json_null(sb);
return sb;
}
strbuf strbuf_json_string_len(strbuf sb, const char *str, size_t strlen)
{
strbuf_putc(sb, '"');
for (; strlen; --strlen, ++str)
_json_char(sb, *str);
strbuf_putc(sb, '"');
return sb;
}
strbuf strbuf_json_hex(strbuf sb, const unsigned char *buf, size_t len)
{
if (buf) {

View File

@ -167,7 +167,8 @@ strbuf strbuf_append_quoted_string(strbuf sb, const char *str);
*/
strbuf strbuf_json_null(strbuf sb);
strbuf strbuf_json_boolean(strbuf sb, int boolean);
strbuf strbuf_json_string(strbuf sb, const char *str);
strbuf strbuf_json_string(strbuf sb, const char *str); // str can be NULL
strbuf strbuf_json_string_len(strbuf sb, const char *str, size_t strlen); // str cannot be NULL
strbuf strbuf_json_hex(strbuf sb, const unsigned char *buf, size_t len);
/* Append a representation of a struct http_range[] array.

View File

@ -1196,8 +1196,28 @@ teardown_MeshmsListMessagesNewSinceArrival() {
}
doc_MeshmsSend="HTTP RESTful send MeshMS message"
Xtest_MeshmsSend() {
:
setup_MeshmsSend() {
IDENTITY_COUNT=2
setup
}
test_MeshmsSend() {
executeOk curl \
--silent --fail --show-error \
--output sendmessage.json \
--basic --user harry:potter \
--form "message=Hello World" \
"http://$addr_localhost:$PORTA/restful/meshms/$SIDA1/$SIDA2/sendmessage"
executeOk_servald meshms list messages $SIDA1 $SIDA2
assertStdoutGrep --matches=1 ':>:Hello World'
executeOk curl \
--silent --fail --show-error \
--output sendmessage.json \
--basic --user ron:weasley \
--form "message=Hello back!" \
"http://$addr_localhost:$PORTA/restful/meshms/$SIDA2/$SIDA1/sendmessage"
executeOk_servald meshms list messages $SIDA1 $SIDA2
assertStdoutGrep --matches=1 ':>:Hello World$'
assertStdoutGrep --matches=1 ':<:Hello back!$'
}
runTests "$@"