mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-18 20:57:56 +00:00
Improve HTTP Content-Type handling
Undo a change from late 2015 that allowed the format=text+binarysig parameter of the rhizome/manifest MIME content-type to be optional -- it is easy to provide that parameter via libcurl, and the lbard code has just been updated to provide it. Make Content-Type handling consistent throughout the Serval DNA code by using 'struct mime_content_type' to represent both parsed (request) and sent (response) Content-Type fields, replacing ad-hoc in-line string literals. Fix some TODOs by adding the "serval/sid", "rhizome/bid" and "rhizome/bundlesecret" MIME types, which remain optional for the time being to preserve REST API compatibility with clients that do not set the Content-Type of their 'bundle-author', 'bundle-id' and 'bundle-secret' parameters.
This commit is contained in:
parent
c64faadb85
commit
29ce8994f2
@ -71,10 +71,19 @@ static struct {
|
||||
#undef VERB_ENTRY
|
||||
};
|
||||
|
||||
const char CONTENT_TYPE_TEXT[] = "text/plain";
|
||||
const char CONTENT_TYPE_HTML[] = "text/html";
|
||||
const char CONTENT_TYPE_JSON[] = "application/json";
|
||||
const char CONTENT_TYPE_BLOB[] = "application/octet-stream";
|
||||
int mime_content_types_are_equal(const struct mime_content_type *a, const struct mime_content_type *b) {
|
||||
return strcmp(a->type, b->type) == 0
|
||||
&& strcmp(a->subtype, b->subtype) == 0
|
||||
&& strcmp(a->multipart_boundary, b->multipart_boundary) == 0
|
||||
&& strcmp(a->charset, b->charset) == 0
|
||||
&& strcmp(a->format, b->format) == 0;
|
||||
}
|
||||
|
||||
const struct mime_content_type CONTENT_TYPE_FAVICON = { .type = "image", .subtype = "vnd.microsoft.icon" };
|
||||
const struct mime_content_type CONTENT_TYPE_TEXT = { .type = "text", .subtype = "plain", .charset = "utf-8" };
|
||||
const struct mime_content_type CONTENT_TYPE_HTML = { .type = "text", .subtype = "html", .charset = "utf-8" };
|
||||
const struct mime_content_type CONTENT_TYPE_JSON = { .type = "application", .subtype = "json" };
|
||||
const struct mime_content_type CONTENT_TYPE_BLOB = { .type = "application", .subtype = "octet-stream" };
|
||||
|
||||
static struct profile_total http_server_stats = {
|
||||
.name = "http_server_poll",
|
||||
@ -2212,10 +2221,12 @@ static const char *http_reason_phrase(int response_code)
|
||||
|
||||
static strbuf strbuf_status_body(strbuf sb, struct http_response *hr)
|
||||
{
|
||||
if ( hr->header.content_type == CONTENT_TYPE_TEXT
|
||||
|| (hr->header.content_type && strcmp(hr->header.content_type, CONTENT_TYPE_TEXT) == 0)
|
||||
if ( hr->header.content_type == &CONTENT_TYPE_TEXT
|
||||
|| ( hr->header.content_type
|
||||
&& strcmp(hr->header.content_type->type, CONTENT_TYPE_TEXT.type) == 0
|
||||
&& strcmp(hr->header.content_type->subtype, CONTENT_TYPE_TEXT.subtype) == 0)
|
||||
) {
|
||||
hr->header.content_type = CONTENT_TYPE_TEXT;
|
||||
hr->header.content_type = &CONTENT_TYPE_TEXT;
|
||||
strbuf_sprintf(sb, "%03u %s", hr->status_code, hr->reason);
|
||||
unsigned i;
|
||||
for (i = 0; i < NELS(hr->result_extra); ++i)
|
||||
@ -2227,10 +2238,12 @@ static strbuf strbuf_status_body(strbuf sb, struct http_response *hr)
|
||||
}
|
||||
strbuf_puts(sb, "\r\n");
|
||||
}
|
||||
else if ( hr->header.content_type == CONTENT_TYPE_JSON
|
||||
|| (hr->header.content_type && strcmp(hr->header.content_type, CONTENT_TYPE_JSON) == 0)
|
||||
else if ( hr->header.content_type == &CONTENT_TYPE_JSON
|
||||
|| ( hr->header.content_type
|
||||
&& strcmp(hr->header.content_type->type, CONTENT_TYPE_JSON.type) == 0
|
||||
&& strcmp(hr->header.content_type->subtype, CONTENT_TYPE_JSON.subtype) == 0)
|
||||
) {
|
||||
hr->header.content_type = CONTENT_TYPE_JSON;
|
||||
hr->header.content_type = &CONTENT_TYPE_JSON;
|
||||
strbuf_sprintf(sb, "{\n \"http_status_code\": %u,\n \"http_status_message\": ", hr->status_code);
|
||||
strbuf_json_string(sb, hr->reason);
|
||||
unsigned i;
|
||||
@ -2244,7 +2257,7 @@ static strbuf strbuf_status_body(strbuf sb, struct http_response *hr)
|
||||
strbuf_puts(sb, "\n}");
|
||||
}
|
||||
else {
|
||||
hr->header.content_type = CONTENT_TYPE_HTML;
|
||||
hr->header.content_type = &CONTENT_TYPE_HTML;
|
||||
strbuf_sprintf(sb, "<html>\n<h1>%03u %s</h1>", hr->status_code, hr->reason);
|
||||
strbuf_puts(sb, "\n<dl>");
|
||||
unsigned i;
|
||||
@ -2323,18 +2336,13 @@ static int _render_response(struct http_request *r)
|
||||
hr.header.content_range_start = 0;
|
||||
}
|
||||
assert(hr.header.content_type != NULL);
|
||||
assert(hr.header.content_type[0]);
|
||||
assert(hr.header.content_type->type[0]);
|
||||
assert(hr.header.content_type->subtype[0]);
|
||||
strbuf_sprintf(sb, "HTTP/1.%d %03u %s\r\n", hr.header.minor_version, hr.status_code, hr.reason);
|
||||
strbuf_puts(sb, "Connection: Close\r\n");
|
||||
strbuf_sprintf(sb, "Server: servald %s\r\n", version_servald);
|
||||
strbuf_sprintf(sb, "Content-Type: %s", hr.header.content_type);
|
||||
if (hr.header.boundary) {
|
||||
strbuf_puts(sb, "; boundary=");
|
||||
if (strchr(hr.header.boundary, '"') || strchr(hr.header.boundary, '\\'))
|
||||
strbuf_append_quoted_string(sb, hr.header.boundary);
|
||||
else
|
||||
strbuf_puts(sb, hr.header.boundary);
|
||||
}
|
||||
strbuf_puts(sb, "Content-Type: ");
|
||||
strbuf_append_mime_content_type(sb, hr.header.content_type);
|
||||
strbuf_puts(sb, "\r\n");
|
||||
if (hr.status_code == 206) {
|
||||
// Must only use result code 206 (Partial Content) if the content is in fact less than the whole
|
||||
@ -2439,7 +2447,8 @@ static void http_request_start_response(struct http_request *r)
|
||||
_release_reserved(r);
|
||||
if (r->response.content || r->response.content_generator) {
|
||||
assert(r->response.header.content_type != NULL);
|
||||
assert(r->response.header.content_type[0]);
|
||||
assert(r->response.header.content_type->type[0]);
|
||||
assert(r->response.header.content_type->subtype[0]);
|
||||
}
|
||||
// If HTTP responses are disabled (eg, for testing purposes) then skip all response construction
|
||||
// and close the connection.
|
||||
@ -2480,19 +2489,20 @@ static void http_request_start_response(struct http_request *r)
|
||||
}
|
||||
|
||||
/* Start sending a static (pre-computed) response back to the client. The response's Content-Type
|
||||
* is set by the 'mime_type' parameter (in the standard format "type/subtype"). The response's
|
||||
* is set by the 'content_type' parameter (in the standard format "type/subtype"). The response's
|
||||
* content is set from the 'body' and 'bytes' parameters, which need not point to persistent data,
|
||||
* ie, the memory pointed to by 'body' is no longer referenced once this function returns.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
void http_request_response_static(struct http_request *r, int result, const char *mime_type, const char *body, uint64_t bytes)
|
||||
void http_request_response_static(struct http_request *r, int result, const struct mime_content_type *content_type, const char *body, uint64_t bytes)
|
||||
{
|
||||
assert(r->phase == RECEIVE);
|
||||
assert(mime_type != NULL);
|
||||
assert(mime_type[0]);
|
||||
assert(content_type != NULL);
|
||||
assert(content_type->type[0]);
|
||||
assert(content_type->subtype[0]);
|
||||
r->response.status_code = result;
|
||||
r->response.header.content_type = mime_type;
|
||||
r->response.header.content_type = content_type;
|
||||
r->response.header.content_range_start = 0;
|
||||
r->response.header.content_length = r->response.header.resource_length = bytes;
|
||||
r->response.content = body;
|
||||
@ -2500,13 +2510,14 @@ void http_request_response_static(struct http_request *r, int result, const char
|
||||
http_request_start_response(r);
|
||||
}
|
||||
|
||||
void http_request_response_generated(struct http_request *r, int result, const char *mime_type, HTTP_CONTENT_GENERATOR generator)
|
||||
void http_request_response_generated(struct http_request *r, int result, const struct mime_content_type *content_type, HTTP_CONTENT_GENERATOR generator)
|
||||
{
|
||||
assert(r->phase == RECEIVE);
|
||||
assert(mime_type != NULL);
|
||||
assert(mime_type[0]);
|
||||
assert(content_type != NULL);
|
||||
assert(content_type->type[0]);
|
||||
assert(content_type->subtype[0]);
|
||||
r->response.status_code = result;
|
||||
r->response.header.content_type = mime_type;
|
||||
r->response.header.content_type = content_type;
|
||||
r->response.content = NULL;
|
||||
r->response.content_generator = generator;
|
||||
http_request_start_response(r);
|
||||
|
@ -60,11 +60,6 @@ http_size_t http_range_bytes(const struct http_range *range, unsigned nranges);
|
||||
|
||||
#define CONTENT_LENGTH_UNKNOWN UINT64_MAX
|
||||
|
||||
extern const char CONTENT_TYPE_TEXT[];
|
||||
extern const char CONTENT_TYPE_HTML[];
|
||||
extern const char CONTENT_TYPE_JSON[];
|
||||
extern const char CONTENT_TYPE_BLOB[];
|
||||
|
||||
struct mime_content_type {
|
||||
char type[64];
|
||||
char subtype[64];
|
||||
@ -73,6 +68,14 @@ struct mime_content_type {
|
||||
char format[31];
|
||||
};
|
||||
|
||||
int mime_content_types_are_equal(const struct mime_content_type *a, const struct mime_content_type *b);
|
||||
|
||||
extern const struct mime_content_type CONTENT_TYPE_FAVICON;
|
||||
extern const struct mime_content_type CONTENT_TYPE_TEXT;
|
||||
extern const struct mime_content_type CONTENT_TYPE_HTML;
|
||||
extern const struct mime_content_type CONTENT_TYPE_JSON;
|
||||
extern const struct mime_content_type CONTENT_TYPE_BLOB;
|
||||
|
||||
struct http_client_authorization {
|
||||
enum http_authorization_scheme { NOAUTH = 0, BASIC } scheme;
|
||||
union {
|
||||
@ -111,7 +114,7 @@ struct http_response_headers {
|
||||
http_size_t content_length;
|
||||
http_size_t content_range_start; // range_end = range_start + content_length - 1
|
||||
http_size_t resource_length; // size of entire resource
|
||||
const char *content_type; // "type/subtype"
|
||||
const struct mime_content_type *content_type; // one of the CONTENT_TYPE_ consts declared above
|
||||
const char *boundary;
|
||||
struct http_origin allow_origin;
|
||||
const char *allow_methods;
|
||||
@ -177,8 +180,8 @@ int http_request_set_response_bufsize(struct http_request *r, size_t bufsiz);
|
||||
void http_request_finalise(struct http_request *r);
|
||||
void http_request_pause_response(struct http_request *r, time_ms_t until);
|
||||
void http_request_resume_response(struct http_request *r);
|
||||
void http_request_response_static(struct http_request *r, int result, const char *mime_type, const char *body, uint64_t bytes);
|
||||
void http_request_response_generated(struct http_request *r, int result, const char *mime_type, HTTP_CONTENT_GENERATOR *);
|
||||
void http_request_response_static(struct http_request *r, int result, const struct mime_content_type *content_type, const char *body, uint64_t bytes);
|
||||
void http_request_response_generated(struct http_request *r, int result, const struct mime_content_type *content_type, HTTP_CONTENT_GENERATOR *);
|
||||
void http_request_simple_response(struct http_request *r, uint16_t result, const char *body);
|
||||
|
||||
typedef int (HTTP_CONTENT_GENERATOR_STRBUF_CHUNKER)(struct http_request *, strbuf);
|
||||
|
21
httpd.c
21
httpd.c
@ -27,6 +27,27 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#define RHIZOME_SERVER_MAX_LIVE_REQUESTS 32
|
||||
|
||||
const struct mime_content_type CONTENT_TYPE_SID_HEX = {
|
||||
.type = "serval",
|
||||
.subtype = "sid",
|
||||
.format = "hex"
|
||||
};
|
||||
const struct mime_content_type CONTENT_TYPE_RHIZOME_BUNDLE_ID = {
|
||||
.type = "rhizome",
|
||||
.subtype = "bid",
|
||||
.format = "hex"
|
||||
};
|
||||
const struct mime_content_type CONTENT_TYPE_RHIZOME_BUNDLE_SECRET = {
|
||||
.type = "rhizome",
|
||||
.subtype = "bundlesecret",
|
||||
.format = "hex"
|
||||
};
|
||||
const struct mime_content_type CONTENT_TYPE_RHIZOME_MANIFEST = {
|
||||
.type = "rhizome",
|
||||
.subtype = "manifest",
|
||||
.format = "text+binarysig"
|
||||
};
|
||||
|
||||
static int httpd_dispatch(struct http_request *);
|
||||
static unsigned int http_request_uuid_counter = 0;
|
||||
static httpd_request * current_httpd_requests = NULL;
|
||||
|
9
httpd.h
9
httpd.h
@ -1,6 +1,7 @@
|
||||
/*
|
||||
Serval DNA Rhizome HTTP interface
|
||||
Serval DNA HTTP interface - common definitions
|
||||
Copyright (C) 2013-2014 Serval Project Inc.
|
||||
Copyright (C) 2017 Flinders University
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
@ -33,6 +34,12 @@ int is_httpd_server_running();
|
||||
extern uint16_t httpd_server_port;
|
||||
extern unsigned int current_httpd_request_count;
|
||||
|
||||
// Some non-standard MIME types for the Content-Type header
|
||||
extern const struct mime_content_type CONTENT_TYPE_SID_HEX;
|
||||
extern const struct mime_content_type CONTENT_TYPE_RHIZOME_BUNDLE_ID;
|
||||
extern const struct mime_content_type CONTENT_TYPE_RHIZOME_BUNDLE_SECRET;
|
||||
extern const struct mime_content_type CONTENT_TYPE_RHIZOME_MANIFEST;
|
||||
|
||||
enum list_phase { LIST_HEADER = 0, LIST_FIRST, LIST_ROWS, LIST_END, LIST_DONE };
|
||||
|
||||
struct form_buf_malloc {
|
||||
|
@ -39,7 +39,7 @@ static HTTP_HANDLER restful_keyring_set;
|
||||
|
||||
static int restful_keyring_(httpd_request *r, const char *remainder)
|
||||
{
|
||||
r->http.response.header.content_type = CONTENT_TYPE_JSON;
|
||||
r->http.response.header.content_type = &CONTENT_TYPE_JSON;
|
||||
int ret = authorize_restful(&r->http);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -134,7 +134,7 @@ static int restful_keyring_identitylist_json(httpd_request *r, const char *remai
|
||||
keyring_enter_pin(keyring, pin);
|
||||
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);
|
||||
http_request_response_generated(&r->http, 200, &CONTENT_TYPE_JSON, restful_keyring_identitylist_json_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -435,7 +435,7 @@ static int restful_meshmb_list(httpd_request *r, const char *remainder)
|
||||
r->u.plylist.rowcount = 0;
|
||||
r->u.plylist.end_offset = r->ui64;
|
||||
|
||||
http_request_response_generated(&r->http, 200, CONTENT_TYPE_JSON, restful_meshmb_list_json_content);
|
||||
http_request_response_generated(&r->http, 200, &CONTENT_TYPE_JSON, restful_meshmb_list_json_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -673,7 +673,7 @@ static int restful_meshmb_feedlist(httpd_request *r, const char *remainder)
|
||||
r->u.meshmb_feeds.generation = meshmb_flush(session->feeds);
|
||||
bzero(&r->u.meshmb_feeds.bundle_id, sizeof r->u.meshmb_feeds.bundle_id);
|
||||
|
||||
http_request_response_generated(&r->http, 200, CONTENT_TYPE_JSON, restful_meshmb_feedlist_json_content);
|
||||
http_request_response_generated(&r->http, 200, &CONTENT_TYPE_JSON, restful_meshmb_feedlist_json_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -878,14 +878,14 @@ static int restful_meshmb_activity(httpd_request *r, const char *remainder)
|
||||
r->u.meshmb_feeds.current_msg_offset = 0;
|
||||
bzero(&r->u.meshmb_feeds.bundle_id, sizeof r->u.meshmb_feeds.bundle_id);
|
||||
|
||||
http_request_response_generated(&r->http, 200, CONTENT_TYPE_JSON, restful_meshmb_activity_json_content);
|
||||
http_request_response_generated(&r->http, 200, &CONTENT_TYPE_JSON, restful_meshmb_activity_json_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
DECLARE_HANDLER("/restful/meshmb/", restful_meshmb_);
|
||||
static int restful_meshmb_(httpd_request *r, const char *remainder)
|
||||
{
|
||||
r->http.response.header.content_type = CONTENT_TYPE_JSON;
|
||||
r->http.response.header.content_type = &CONTENT_TYPE_JSON;
|
||||
if (!is_rhizome_http_enabled())
|
||||
return 404;
|
||||
int ret = authorize_restful(&r->http);
|
||||
|
@ -150,7 +150,7 @@ static HTTP_HANDLER restful_meshms_read_to_offset;
|
||||
|
||||
static int restful_meshms_(httpd_request *r, const char *remainder)
|
||||
{
|
||||
r->http.response.header.content_type = CONTENT_TYPE_JSON;
|
||||
r->http.response.header.content_type = &CONTENT_TYPE_JSON;
|
||||
if (!is_rhizome_http_enabled())
|
||||
return 404;
|
||||
int ret = authorize_restful(&r->http);
|
||||
@ -246,7 +246,7 @@ static int restful_meshms_conversationlist_json(httpd_request *r, const char *re
|
||||
return http_request_meshms_response(r, 0, NULL, status);
|
||||
if (r->u.mclist.conv != NULL)
|
||||
meshms_conversation_iterator_start(&r->u.mclist.iter, r->u.mclist.conv);
|
||||
http_request_response_generated(&r->http, 200, CONTENT_TYPE_JSON, restful_meshms_conversationlist_json_content);
|
||||
http_request_response_generated(&r->http, 200, &CONTENT_TYPE_JSON, restful_meshms_conversationlist_json_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -363,7 +363,7 @@ static int restful_meshms_messagelist_json(httpd_request *r, const char *remaind
|
||||
enum meshms_status status;
|
||||
if (meshms_failed(status = reopen_meshms_message_iterator(r)))
|
||||
return http_request_meshms_response(r, 0, NULL, status);
|
||||
http_request_response_generated(&r->http, 200, CONTENT_TYPE_JSON, restful_meshms_messagelist_json_content);
|
||||
http_request_response_generated(&r->http, 200, &CONTENT_TYPE_JSON, restful_meshms_messagelist_json_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -381,7 +381,7 @@ static int restful_meshms_newsince_messagelist_json(httpd_request *r, const char
|
||||
if (meshms_failed(status = reopen_meshms_message_iterator(r)))
|
||||
return http_request_meshms_response(r, 0, NULL, status);
|
||||
r->u.msglist.end_time = gettime_ms() + config.api.restful.newsince_timeout * 1000;
|
||||
http_request_response_generated(&r->http, 200, CONTENT_TYPE_JSON, restful_meshms_messagelist_json_content);
|
||||
http_request_response_generated(&r->http, 200, &CONTENT_TYPE_JSON, restful_meshms_messagelist_json_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ static void http_request_rhizome_bundle_status_response(httpd_request *r, struct
|
||||
break;
|
||||
}
|
||||
if (m)
|
||||
http_request_response_static(&r->http, http_status, CONTENT_TYPE_TEXT, (const char *)m->manifestdata, m->manifest_all_bytes);
|
||||
http_request_response_static(&r->http, http_status, &CONTENT_TYPE_TEXT, (const char *)m->manifestdata, m->manifest_all_bytes);
|
||||
else
|
||||
http_request_simple_response(&r->http, http_status, rhizome_bundle_result_message(result));
|
||||
}
|
||||
@ -188,7 +188,7 @@ int rhizome_direct_enquiry_end(struct http_request *hr)
|
||||
if (http_request_set_response_bufsize(&r->http, bytes) == -1)
|
||||
http_request_simple_response(&r->http, 500, "Internal Error: Out of memory");
|
||||
else
|
||||
http_request_response_static(&r->http, 200, "binary/octet-stream", (const char *)c->buffer, bytes);
|
||||
http_request_response_static(&r->http, 200, &CONTENT_TYPE_BLOB, (const char *)c->buffer, bytes);
|
||||
rhizome_direct_bundle_iterator_free(&c);
|
||||
} else
|
||||
http_request_simple_response(&r->http, 500, "Internal Error: No response to enquiry");
|
||||
@ -504,10 +504,9 @@ void rhizome_direct_http_dispatch(rhizome_direct_sync_request *r)
|
||||
strbuf_sprintf(content_preamble,
|
||||
"--%s\r\n"
|
||||
"Content-Disposition: form-data; name=\"data\"; filename=\"IHAVEs\"\r\n"
|
||||
"Content-Type: %s\r\n"
|
||||
"\r\n",
|
||||
boundary, CONTENT_TYPE_BLOB
|
||||
);
|
||||
"Content-Type: ", boundary);
|
||||
strbuf_append_mime_content_type(content_preamble, &CONTENT_TYPE_BLOB);
|
||||
strbuf_puts(content_preamble, "\r\n\r\n");
|
||||
strbuf_sprintf(content_postamble, "\r\n--%s--\r\n", boundary);
|
||||
assert(!strbuf_overrun(content_preamble));
|
||||
assert(!strbuf_overrun(content_postamble));
|
||||
|
@ -50,7 +50,7 @@ static int rhizome_file_page(httpd_request *r, const char *remainder)
|
||||
return ret;
|
||||
// backwards compatibility, rhizome_fetch used to allow HTTP/1.0 responses only
|
||||
r->http.response.header.minor_version=0;
|
||||
http_request_response_generated(&r->http, 200, CONTENT_TYPE_BLOB, rhizome_payload_content);
|
||||
http_request_response_generated(&r->http, 200, &CONTENT_TYPE_BLOB, rhizome_payload_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ static int manifest_by_prefix_page(httpd_request *r, const char *remainder)
|
||||
case RHIZOME_BUNDLE_STATUS_SAME:
|
||||
// backwards compatibility, rhizome_fetch used to allow HTTP/1.0 responses only
|
||||
r->http.response.header.minor_version=0;
|
||||
http_request_response_static(&r->http, 200, CONTENT_TYPE_BLOB, (const char *)r->manifest->manifestdata, r->manifest->manifest_all_bytes);
|
||||
http_request_response_static(&r->http, 200, &CONTENT_TYPE_BLOB, (const char *)r->manifest->manifestdata, r->manifest->manifest_all_bytes);
|
||||
return 1;
|
||||
case RHIZOME_BUNDLE_STATUS_NEW:
|
||||
return 404;
|
||||
@ -97,6 +97,6 @@ static int rhizome_status_page(httpd_request *r, const char *remainder)
|
||||
strbuf_puts(b, "</body></html>");
|
||||
if (strbuf_overrun(b))
|
||||
return -1;
|
||||
http_request_response_static(&r->http, 200, CONTENT_TYPE_HTML, buf, strbuf_len(b));
|
||||
http_request_response_static(&r->http, 200, &CONTENT_TYPE_HTML, buf, strbuf_len(b));
|
||||
return 1;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "serval.h"
|
||||
#include "rhizome.h"
|
||||
#include "conf.h"
|
||||
#include "httpd.h"
|
||||
#include "str.h"
|
||||
@ -226,13 +227,13 @@ static int restful_open_cursor(httpd_request *r)
|
||||
if (ret == -1)
|
||||
return http_request_rhizome_response(r, 500, "Failed to open list");
|
||||
|
||||
http_request_response_generated(&r->http, 200, CONTENT_TYPE_JSON, restful_rhizome_bundlelist_json_content);
|
||||
http_request_response_generated(&r->http, 200, &CONTENT_TYPE_JSON, restful_rhizome_bundlelist_json_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int restful_rhizome_bundlelist_json(httpd_request *r, const char *remainder)
|
||||
{
|
||||
r->http.response.header.content_type = CONTENT_TYPE_JSON;
|
||||
r->http.response.header.content_type = &CONTENT_TYPE_JSON;
|
||||
r->http.render_extra_headers = render_manifest_headers;
|
||||
if (!is_rhizome_http_enabled())
|
||||
return 404;
|
||||
@ -259,7 +260,7 @@ static int restful_rhizome_bundlelist_json_content(struct http_request *hr, unsi
|
||||
|
||||
static int restful_rhizome_newsince(httpd_request *r, const char *remainder)
|
||||
{
|
||||
r->http.response.header.content_type = CONTENT_TYPE_JSON;
|
||||
r->http.response.header.content_type = &CONTENT_TYPE_JSON;
|
||||
if (!is_rhizome_http_enabled())
|
||||
return 404;
|
||||
int ret = authorize_restful(&r->http);
|
||||
@ -418,7 +419,7 @@ static int insert_mime_part_body(struct http_request *, char *, size_t);
|
||||
|
||||
static int restful_rhizome_insert(httpd_request *r, const char *remainder)
|
||||
{
|
||||
r->http.response.header.content_type = CONTENT_TYPE_JSON;
|
||||
r->http.response.header.content_type = &CONTENT_TYPE_JSON;
|
||||
r->http.render_extra_headers = render_manifest_headers;
|
||||
if (!is_rhizome_http_enabled())
|
||||
return 404;
|
||||
@ -583,7 +584,11 @@ static int insert_mime_part_header(struct http_request *hr, const struct mime_pa
|
||||
// Reject a request if this parameter comes after the manifest part.
|
||||
if (r->u.insert.received_manifest || r->u.insert.importing)
|
||||
return http_response_form_part(r, 400, "Spurious", PART_AUTHOR, NULL, 0);
|
||||
// TODO enforce correct content type
|
||||
if (!h->content_type.type[0])
|
||||
; // missing Content-Type defaults to CONTENT_TYPE_SID_HEX
|
||||
// TODO deprecate this default and insist that Content-Type be supplied
|
||||
else if (!mime_content_types_are_equal(&h->content_type, &CONTENT_TYPE_SID_HEX))
|
||||
return http_response_form_part(r, 415, "Unsupported Content-Type in", PART_AUTHOR, NULL, 0);
|
||||
r->u.insert.current_part = PART_AUTHOR;
|
||||
assert(r->u.insert.author_hex_len == 0);
|
||||
}
|
||||
@ -593,7 +598,11 @@ static int insert_mime_part_header(struct http_request *hr, const struct mime_pa
|
||||
// Reject a request if this parameter comes after the manifest part.
|
||||
if (r->u.insert.received_manifest || r->u.insert.importing)
|
||||
return http_response_form_part(r, 400, "Spurious", PART_SECRET, NULL, 0);
|
||||
// TODO enforce correct content type
|
||||
if (!h->content_type.type[0])
|
||||
; // missing Content-Type defaults to CONTENT_TYPE_RHIZOME_BUNDLE_SECRET
|
||||
// TODO deprecate this default and insist that Content-Type be supplied
|
||||
else if (!mime_content_types_are_equal(&h->content_type, &CONTENT_TYPE_RHIZOME_BUNDLE_SECRET))
|
||||
return http_response_form_part(r, 415, "Unsupported Content-Type in", PART_SECRET, NULL, 0);
|
||||
r->u.insert.current_part = PART_SECRET;
|
||||
assert(r->u.insert.secret_text_len == 0);
|
||||
}
|
||||
@ -603,7 +612,11 @@ static int insert_mime_part_header(struct http_request *hr, const struct mime_pa
|
||||
// Reject a request if this parameter comes after the manifest part.
|
||||
if (r->u.insert.received_manifest || r->u.insert.importing)
|
||||
return http_response_form_part(r, 400, "Spurious", PART_BUNDLEID, NULL, 0);
|
||||
// TODO enforce correct content type
|
||||
if (!h->content_type.type[0])
|
||||
; // missing Content-Type defaults to CONTENT_TYPE_RHIZOME_BUNDLE_ID
|
||||
// TODO deprecate this default and insist that Content-Type be supplied
|
||||
else if (!mime_content_types_are_equal(&h->content_type, &CONTENT_TYPE_RHIZOME_BUNDLE_ID))
|
||||
return http_response_form_part(r, 415, "Unsupported Content-Type in", PART_BUNDLEID, NULL, 0);
|
||||
r->u.insert.current_part = PART_BUNDLEID;
|
||||
assert(r->u.insert.bid_text_len == 0);
|
||||
}
|
||||
@ -612,13 +625,8 @@ static int insert_mime_part_header(struct http_request *hr, const struct mime_pa
|
||||
if (r->u.insert.received_manifest)
|
||||
return http_response_form_part(r, 400, "Duplicate", PART_MANIFEST, NULL, 0);
|
||||
form_buf_malloc_init(&r->u.insert.manifest, MAX_MANIFEST_BYTES);
|
||||
if ( strcmp(h->content_type.type, "rhizome") != 0
|
||||
|| strcmp(h->content_type.subtype, "manifest") != 0
|
||||
)
|
||||
if (!mime_content_types_are_equal(&h->content_type, &CONTENT_TYPE_RHIZOME_MANIFEST))
|
||||
return http_response_form_part(r, 415, "Unsupported Content-Type in", PART_MANIFEST, NULL, 0);
|
||||
if ((strcmp(h->content_type.format, "text+binarysig") != 0)
|
||||
&&strlen(h->content_type.format))
|
||||
return http_response_form_part(r, 415, "Unsupported rhizome/manifest format in", PART_MANIFEST, NULL, 0);
|
||||
r->u.insert.current_part = PART_MANIFEST;
|
||||
}
|
||||
else if (strcmp(h->content_disposition.name, PART_PAYLOAD) == 0) {
|
||||
@ -880,7 +888,7 @@ static int restful_rhizome_insert_end(struct http_request *hr)
|
||||
return http_request_rhizome_response(r, http_status, NULL);
|
||||
}else{
|
||||
rhizome_authenticate_author(r->manifest);
|
||||
http_request_response_static(&r->http, http_status, "rhizome-manifest/text",
|
||||
http_request_response_static(&r->http, http_status, &CONTENT_TYPE_RHIZOME_MANIFEST,
|
||||
(const char *)r->manifest->manifestdata, r->manifest->manifest_all_bytes
|
||||
);
|
||||
}
|
||||
@ -893,7 +901,7 @@ static HTTP_HANDLER restful_rhizome_bid_decrypted_bin;
|
||||
|
||||
static int restful_rhizome_(httpd_request *r, const char *remainder)
|
||||
{
|
||||
r->http.response.header.content_type = CONTENT_TYPE_JSON;
|
||||
r->http.response.header.content_type = &CONTENT_TYPE_JSON;
|
||||
r->http.render_extra_headers = render_manifest_headers;
|
||||
if (!is_rhizome_http_enabled())
|
||||
return 404;
|
||||
@ -949,7 +957,7 @@ static int restful_rhizome_bid_rhm(httpd_request *r, const char *remainder)
|
||||
return 404;
|
||||
if (r->manifest == NULL)
|
||||
return http_request_rhizome_response(r, 404, "Bundle not found"); // Not Found
|
||||
http_request_response_static(&r->http, 200, "rhizome-manifest/text",
|
||||
http_request_response_static(&r->http, 200, &CONTENT_TYPE_RHIZOME_MANIFEST,
|
||||
(const char *)r->manifest->manifestdata, r->manifest->manifest_all_bytes
|
||||
);
|
||||
return 1;
|
||||
@ -962,13 +970,13 @@ static int restful_rhizome_bid_raw_bin(httpd_request *r, const char *remainder)
|
||||
if (r->manifest == NULL)
|
||||
return http_request_rhizome_response(r, 404, "Bundle not found"); // Not Found
|
||||
if (r->manifest->filesize == 0) {
|
||||
http_request_response_static(&r->http, 200, CONTENT_TYPE_BLOB, "", 0);
|
||||
http_request_response_static(&r->http, 200, &CONTENT_TYPE_BLOB, "", 0);
|
||||
return 1;
|
||||
}
|
||||
int ret = rhizome_response_content_init_filehash(r, &r->manifest->filehash);
|
||||
if (ret)
|
||||
return ret;
|
||||
http_request_response_generated(&r->http, 200, CONTENT_TYPE_BLOB, rhizome_payload_content);
|
||||
http_request_response_generated(&r->http, 200, &CONTENT_TYPE_BLOB, rhizome_payload_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -980,14 +988,14 @@ static int restful_rhizome_bid_decrypted_bin(httpd_request *r, const char *remai
|
||||
return http_request_rhizome_response(r, 404, "Bundle not found"); // Not Found
|
||||
if (r->manifest->filesize == 0) {
|
||||
// TODO use Content Type from manifest (once it is implemented)
|
||||
http_request_response_static(&r->http, 200, CONTENT_TYPE_BLOB, "", 0);
|
||||
http_request_response_static(&r->http, 200, &CONTENT_TYPE_BLOB, "", 0);
|
||||
return 1;
|
||||
}
|
||||
int ret = rhizome_response_content_init_payload(r, r->manifest);
|
||||
if (ret)
|
||||
return ret;
|
||||
// TODO use Content Type from manifest (once it is implemented)
|
||||
http_request_response_generated(&r->http, 200, CONTENT_TYPE_BLOB, rhizome_payload_content);
|
||||
http_request_response_generated(&r->http, 200, &CONTENT_TYPE_BLOB, rhizome_payload_content);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "conf.h"
|
||||
#include "overlay_address.h"
|
||||
#include "overlay_interface.h"
|
||||
#include "str.h"
|
||||
#include "os.h"
|
||||
#include "route_link.h"
|
||||
|
||||
@ -67,7 +68,7 @@ static int root_page(httpd_request *r, const char *remainder)
|
||||
WHY("HTTP Root page buffer overrun");
|
||||
return 500;
|
||||
}
|
||||
http_request_response_static(&r->http, 200, CONTENT_TYPE_HTML, temp, strbuf_len(b));
|
||||
http_request_response_static(&r->http, 200, &CONTENT_TYPE_HTML, temp, strbuf_len(b));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -75,7 +76,7 @@ static int fav_icon_header(httpd_request *r, const char *remainder)
|
||||
{
|
||||
if (*remainder)
|
||||
return 404;
|
||||
http_request_response_static(&r->http, 200, "image/vnd.microsoft.icon", (const char *)favicon_bytes, favicon_len);
|
||||
http_request_response_static(&r->http, 200, &CONTENT_TYPE_FAVICON, (const char *)favicon_bytes, favicon_len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -96,7 +97,7 @@ static int neighbour_page(httpd_request *r, const char *remainder)
|
||||
strbuf_puts(b, "</body></html>");
|
||||
if (strbuf_overrun(b))
|
||||
return -1;
|
||||
http_request_response_static(&r->http, 200, CONTENT_TYPE_HTML, buf, strbuf_len(b));
|
||||
http_request_response_static(&r->http, 200, &CONTENT_TYPE_HTML, buf, strbuf_len(b));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -114,7 +115,7 @@ static int interface_page(httpd_request *r, const char *remainder)
|
||||
strbuf_puts(b, "</body></html>");
|
||||
if (strbuf_overrun(b))
|
||||
return -1;
|
||||
http_request_response_static(&r->http, 200, CONTENT_TYPE_HTML, buf, strbuf_len(b));
|
||||
http_request_response_static(&r->http, 200, &CONTENT_TYPE_HTML, buf, strbuf_len(b));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -170,6 +171,6 @@ static int static_page(httpd_request *r, const char *remainder)
|
||||
}
|
||||
}
|
||||
r->u.file.offset=r->http.response.header.content_range_start;
|
||||
http_request_response_generated(&r->http, 200, CONTENT_TYPE_HTML, static_file_generator);
|
||||
http_request_response_generated(&r->http, 200, &CONTENT_TYPE_HTML, static_file_generator);
|
||||
return 1;
|
||||
}
|
||||
|
@ -635,6 +635,15 @@ strbuf strbuf_append_quoted_string(strbuf sb, const char *str)
|
||||
return sb;
|
||||
}
|
||||
|
||||
strbuf strbuf_append_token_or_quoted_string(strbuf sb, const char *str)
|
||||
{
|
||||
for (const char *s = str; *s; ++s)
|
||||
if (!is_http_token(*s))
|
||||
return strbuf_append_quoted_string(sb, str);
|
||||
strbuf_puts(sb, str);
|
||||
return sb;
|
||||
}
|
||||
|
||||
static void _html_char(strbuf sb, char c)
|
||||
{
|
||||
if (c == '&')
|
||||
@ -943,15 +952,15 @@ strbuf strbuf_append_mime_content_type(strbuf sb, const struct mime_content_type
|
||||
strbuf_puts(sb, ct->subtype);
|
||||
if (ct->charset[0]) {
|
||||
strbuf_puts(sb, "; charset=");
|
||||
strbuf_append_quoted_string(sb, ct->charset);
|
||||
strbuf_append_token_or_quoted_string(sb, ct->charset);
|
||||
}
|
||||
if (ct->multipart_boundary[0]) {
|
||||
strbuf_puts(sb, "; boundary=");
|
||||
strbuf_append_quoted_string(sb, ct->multipart_boundary);
|
||||
strbuf_append_token_or_quoted_string(sb, ct->multipart_boundary);
|
||||
}
|
||||
if (ct->format[0]) {
|
||||
strbuf_puts(sb, "; format=");
|
||||
strbuf_append_quoted_string(sb, ct->format);
|
||||
strbuf_append_token_or_quoted_string(sb, ct->format);
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
@ -211,6 +211,13 @@ strbuf strbuf_append_file_meta(strbuf sb, const struct file_meta *metap);
|
||||
*/
|
||||
strbuf strbuf_append_quoted_string(strbuf sb, const char *str);
|
||||
|
||||
/* Append a string using HTTP token|quoted-string format: if it contains only
|
||||
* token characters, then unmodified, otherwise as a quoted-string
|
||||
* (strbuf_append_quoted_string).
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
strbuf strbuf_append_token_or_quoted_string(strbuf sb, const char *str);
|
||||
|
||||
/* Escape HTML entities.
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user