From fe7373e442239a540fea0965c2dade50c9155cce Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Mon, 17 Oct 2016 23:08:02 +0200 Subject: [PATCH] [httpd] Implement httpd_send_error, a modified evhttp_send_error, which can include CORS headers (credit @bjoernricks and libevent) --- src/httpd.c | 39 ++++++++++++++++++++++++++++++++++++++- src/httpd.h | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/httpd.c b/src/httpd.c index 8a7573fa..899dce1c 100644 --- a/src/httpd.c +++ b/src/httpd.c @@ -86,6 +86,11 @@ #define STREAM_CHUNK_SIZE (64 * 1024) #define WEBFACE_ROOT DATADIR "/webface/" +#define ERR_PAGE "\n\n" \ + "%d %s\n" \ + "\n\n" \ + "

%s

\n" \ + "\n\n" struct content_type_map { char *ext; @@ -758,7 +763,6 @@ httpd_gzip_deflate(struct evbuffer *in) return NULL; } -/* Thread: httpd */ void httpd_send_reply(struct evhttp_request *req, int code, const char *reason, struct evbuffer *evbuf, enum httpd_send_flags flags) { @@ -800,6 +804,39 @@ httpd_send_reply(struct evhttp_request *req, int code, const char *reason, struc } } +// This is a modified version of evhttp_send_error (credit libevent) +void +httpd_send_error(struct evhttp_request* req, int error, const char* reason) +{ + struct evkeyvalq *output_headers; + struct evbuffer *evbuf; + + if (!allow_origin) + { + evhttp_send_error(req, error, reason); + return; + } + + output_headers = evhttp_request_get_output_headers(req); + + evhttp_clear_headers(output_headers); + + evhttp_add_header(output_headers, "Access-Control-Allow-Origin", allow_origin); + evhttp_add_header(output_headers, "Content-Type", "text/html"); + evhttp_add_header(output_headers, "Connection", "close"); + + evbuf = evbuffer_new(); + if (!evbuf) + DPRINTF(E_LOG, L_HTTPD, "Could not allocate evbuffer for error page\n"); + else + evbuffer_add_printf(evbuf, ERR_PAGE, error, reason, reason); + + evhttp_send_reply(req, error, reason, evbuf); + + if (evbuf) + evbuffer_free(evbuf); +} + /* Thread: httpd */ static int path_is_legal(char *path) diff --git a/src/httpd.h b/src/httpd.h index 3cb5c490..7cd0f8fd 100644 --- a/src/httpd.h +++ b/src/httpd.h @@ -13,13 +13,45 @@ enum httpd_send_flags void httpd_stream_file(struct evhttp_request *req, int id); -// Returns a pointer to an evbuffer with gzipped. Must be freed by caller. +/* + * Gzips an evbuffer + * + * @in in Data to be compressed + * @return Compressed data - must be freed by caller + */ struct evbuffer * httpd_gzip_deflate(struct evbuffer *in); +/* + * This wrapper around evhttp_send_reply should be used whenever a request may + * come from a browser. It will automatically gzip if feasible, but the caller + * may direct it not to. It will set CORS headers as appropriate. Should be + * thread safe. + * + * @in req The evhttp request struct + * @in code HTTP code, e.g. 200 + * @in reason A brief explanation of the error - if NULL the standard meaning + of the error code will be used + * @in evbuf Data for the response body + * @in flags See flags above + */ void httpd_send_reply(struct evhttp_request *req, int code, const char *reason, struct evbuffer *evbuf, enum httpd_send_flags flags); +/* + * This is a substitute for evhttp_send_error that should be used whenever an + * error may be returned to a browser. It will set CORS headers as appropriate, + * which is not possible with evhttp_send_error, because it clears the headers. + * Should be thread safe. + * + * @in req The evhttp request struct + * @in error HTTP code, e.g. 200 + * @in reason A brief explanation of the error - if NULL the standard meaning + of the error code will be used + */ +void +httpd_send_error(struct evhttp_request *req, int error, const char *reason); + char * httpd_fixup_uri(struct evhttp_request *req);