diff options
| -rw-r--r-- | docs/man/libnng.3.adoc | 3 | ||||
| -rw-r--r-- | docs/man/nng_http_server_res_error.3http.adoc | 63 | ||||
| -rw-r--r-- | docs/man/nng_http_server_set_error_file.3http.adoc | 73 | ||||
| -rw-r--r-- | docs/man/nng_http_server_set_error_page.3http.adoc | 69 | ||||
| -rw-r--r-- | src/supplemental/http/http.h | 23 | ||||
| -rw-r--r-- | src/supplemental/http/http_api.h | 21 | ||||
| -rw-r--r-- | src/supplemental/http/http_msg.c | 20 | ||||
| -rw-r--r-- | src/supplemental/http/http_public.c | 41 | ||||
| -rw-r--r-- | src/supplemental/http/http_server.c | 148 | ||||
| -rw-r--r-- | tests/httpserver.c | 23 |
10 files changed, 471 insertions, 13 deletions
diff --git a/docs/man/libnng.3.adoc b/docs/man/libnng.3.adoc index 21a34a6a..70fd3be2 100644 --- a/docs/man/libnng.3.adoc +++ b/docs/man/libnng.3.adoc @@ -341,7 +341,10 @@ These functions are intended for use with HTTP server applications. |<<nng_http_server_get_tls.3http#,nng_http_server_get_tls()>>|get HTTP server TLS configuration |<<nng_http_server_hold.3http#,nng_http_server_get_tls()>>|get and hold HTTP server instance |<<nng_http_server_release.3http#,nng_http_server_get_tls()>>|release HTTP server instance +|<<nng_http_server_set_error_file.3http#,nng_http_server_set_error_file()>>|set custom HTTP error file +|<<nng_http_server_set_error_page.3http#,nng_http_server_set_error_page()>>|set custom HTTP error page |<<nng_http_server_set_tls.3http#,nng_http_server_set_tls()>>|set HTTP server TLS configuration +|<<nng_http_server_res_error.3http#,nng_http_server_res_error()>>|use HTTP server error page |<<nng_http_server_start.3http#,nng_http_server_start()>>|start HTTP server |<<nng_http_server_stop.3http#,nng_http_server_stop()>>|stop HTTP server |=== diff --git a/docs/man/nng_http_server_res_error.3http.adoc b/docs/man/nng_http_server_res_error.3http.adoc new file mode 100644 index 00000000..a62628f7 --- /dev/null +++ b/docs/man/nng_http_server_res_error.3http.adoc @@ -0,0 +1,63 @@ += nng_http_server_res_error(3http) +// +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_http_server_res_error - use HTTP server error page + +== SYNOPSIS + +[source, c] +---- +#include <nng/nng.h> +#include <nng/supplemental/http/http.h> + +int nng_http_server_set_error_file(nng_http_server *server, + nng_http_res *response); +---- + +== DESCRIPTION + +The `nng_http_server_res_error()` sets the body of _response_ +to _server_'s error page, which may have been customized using the +`<<nng_http_server_set_error_file.3http#,nng_http_server_error_file()>>` +or +`<<nng_http_server_set_error_page.3http#,nng_http_server_error_page()>>` +functions. + +The status code of the _response_ should have already been set, either +implicitly by allocating it with +`<<nng_http_res_alloc_error.3http#,nng_http_res_alloc_error()>>`, +or by calling +`<<nng_http_res_set_status.3http#,nng_http_res_set_status()>>`. + +Any content body previously set for _response_ will be overridden by +this function. + +== RETURN VALUES + +This function returns 0 on success, and non-zero otherwise. + +== ERRORS + +[horizontal] +`NNG_ENOMEM`:: Insufficient free memory exists. +`NNG_ENOTSUP`:: HTTP not supported. + +== SEE ALSO + +[.text-left] +<<nng_http_res_alloc_error.3http#,nng_http_res_alloc_error(3http)>>, +<<nng_http_server_hold.3http#,nng_http_server_hold(3http)>>, +<<nng_http_server_set_error_file.3http#,nng_http_server_set_error_file(3http)>>, +<<nng_http_server_set_error_page.3http#,nng_http_server_set_error_page(3http)>>, +<<nng_strerror.3#,nng_strerror(3)>>, +<<nng.7#,nng(7)>> diff --git a/docs/man/nng_http_server_set_error_file.3http.adoc b/docs/man/nng_http_server_set_error_file.3http.adoc new file mode 100644 index 00000000..dde8d980 --- /dev/null +++ b/docs/man/nng_http_server_set_error_file.3http.adoc @@ -0,0 +1,73 @@ += nng_http_server_set_error_file(3http) +// +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_http_server_set_error_file - set custom HTTP error file + +== SYNOPSIS + +[source, c] +---- +#include <nng/nng.h> +#include <nng/supplemental/http/http.h> + +int nng_http_server_set_error_file(nng_http_server *server, + uint16_t code, const char *path); +---- + +== DESCRIPTION + +The `nng_http_server_set_error_file()` sets an error page to be used +for HTTP status _code_ on the server instance _server_. +The body content of the HTTP responses will contain the file contents of +the file located at _path_, which should be an HTML file. + +The custom HTML content will be used when the server is returning an +internally generated error response, or is returning an error response +that was allocated with the +`<<nng_http_res_alloc_error.3http#,nng_http_res_alloc_error()>>` +function. +This HTML content will also be used if the application calls the +`<<nng_http_server_res_error.3http#,nng_http_server_res_error()>>`. +The last custom error page set for _code_ by either this function or +`<<nng_http_server_set_error_page.3http#,nng_http_server_error_page()>>` +will be used. + +NOTE: Error responses that have their body content changed after allocation, +or that are written directly by the application, will not use the body +content supplied here. + +NOTE: The file contents of _path_ are read when this function is called. +Therefore, if the file contents are changed, then this function should +be called again to update the error page. + +== RETURN VALUES + +This function returns 0 on success, and non-zero otherwise. + +== ERRORS + +[horizontal] +`NNG_ENOENT`:: The file named by _path_ does not exist. +`NNG_EPERM`:: No permission to read the file named by _path_. +`NNG_ENOMEM`:: Insufficient free memory exists. +`NNG_ENOTSUP`:: HTTP not supported. + +== SEE ALSO + +[.text-left] +<<nng_http_res_alloc_error.3http#,nng_http_res_alloc_error(3http)>>, +<<nng_http_server_hold.3http#,nng_http_server_hold(3http)>>, +<<nng_http_server_res_error.3http#,nng_http_server_res_error(3http)>>, +<<nng_http_server_set_error_page.3http#,nng_http_server_set_error_page(3http)>>, +<<nng_strerror.3#,nng_strerror(3)>>, +<<nng.7#,nng(7)>> diff --git a/docs/man/nng_http_server_set_error_page.3http.adoc b/docs/man/nng_http_server_set_error_page.3http.adoc new file mode 100644 index 00000000..271b9d99 --- /dev/null +++ b/docs/man/nng_http_server_set_error_page.3http.adoc @@ -0,0 +1,69 @@ += nng_http_server_set_error_page(3http) +// +// Copyright 2018 Staysail Systems, Inc. <info@staysail.tech> +// Copyright 2018 Capitar IT Group BV <info@capitar.com> +// +// This document is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +== NAME + +nng_http_server_set_error_page - set custom HTTP error page + +== SYNOPSIS + +[source, c] +---- +#include <nng/nng.h> +#include <nng/supplemental/http/http.h> + +int nng_http_server_set_error_page(nng_http_server *server, + uint16_t code, const char *html); +---- + +== DESCRIPTION + +The `nng_http_server_set_error_page()` sets an error page to be used +for HTTP status _code_ on the server instance _server_. +The body content of the HTTP responses will contain _html_. + +The custom HTML content will be used when the server is returning an +internally generated error response, or is returning an error response +that was allocated with the +`<<nng_http_res_alloc_error.3http#,nng_http_res_alloc_error()>>` +function. +This HTML content will also be used if the application calls the +`<<nng_http_server_res_error.3http#,nng_http_server_res_error()>>`. +The last custom error page set for _code_ by either this function or +`<<nng_http_server_set_error_file.3http#,nng_http_server_error_file()>>` +will be used. + +NOTE: Error responses that have their body content changed after allocation, +or that are written directly by the application, will not use the body +content supplied here. + +The supplied HTML content is copied by this function, and may be reused +after this function returns. + +== RETURN VALUES + +This function returns 0 on success, and non-zero otherwise. + +== ERRORS + +[horizontal] +`NNG_ENOMEM`:: Insufficient free memory exists. +`NNG_ENOTSUP`:: HTTP not supported. + +== SEE ALSO + +[.text-left] +<<nng_http_res_alloc_error.3http#,nng_http_res_alloc_error(3http)>>, +<<nng_http_server_hold.3http#,nng_http_server_hold(3http)>>, +<<nng_http_server_res_error.3http#,nng_http_server_res_error(3http)>>, +<<nng_http_server_set_error_file.3http#,nng_http_server_set_error_file(3http)>>, +<<nng_strerror.3#,nng_strerror(3)>>, +<<nng.7#,nng(7)>> diff --git a/src/supplemental/http/http.h b/src/supplemental/http/http.h index f6a45df7..21e6b5de 100644 --- a/src/supplemental/http/http.h +++ b/src/supplemental/http/http.h @@ -407,6 +407,29 @@ NNG_DECL int nng_http_server_set_tls( NNG_DECL int nng_http_server_get_tls( nng_http_server *, struct nng_tls_config **); +// nng_http_server_set_error_page sets a custom error page (HTML) content +// to be sent for the given error code. This is used when the error is +// generated internally by the framework, or when the application returns +// the response back to the server via the handler's aio, and the response +// was allocated with nng_http_res_alloc_error. If the response was not +// allocated this way, or the application writes the response itself instead +// of letting the server do so, then this setting will be ignored. +NNG_DECL int nng_http_server_set_error_page( + nng_http_server *, uint16_t, const char *); + +// nng_http_server_set_error_file works like nng_http_server_error_page, +// except that the content is loaded from the named file path. The contents +// are loaded at the time this function is called, so this function should be +// called anytime the contents of the named file have changed. +NNG_DECL int nng_http_server_set_error_file( + nng_http_server *, uint16_t, const char *); + +// nng_http_server_res_error takes replaces the body of the response with +// a custom error page previously set for the server, using the status +// of the response. The response must have the status set first using +// nng_http_res_set_status or implicitly via nng_http_res_alloc_error. +NNG_DECL int nng_http_server_res_error(nng_http_server *, nng_http_res *); + // nng_http_hijack is intended to be called by a handler that wishes to // take over the processing of the HTTP session -- usually to change protocols // (such as in the case of websocket). The caller is responsible for the diff --git a/src/supplemental/http/http_api.h b/src/supplemental/http/http_api.h index f1a5c0fa..4b515ca5 100644 --- a/src/supplemental/http/http_api.h +++ b/src/supplemental/http/http_api.h @@ -30,6 +30,9 @@ typedef struct nng_http_client nni_http_client; // These functions are private to the internal framework, and really should // not be used elsewhere. + +extern const char *nni_http_reason(uint16_t); + extern int nni_http_req_init(nni_http_req **); extern void nni_http_req_reset(nni_http_req *); extern int nni_http_req_get_buf(nni_http_req *, void **, size_t *); @@ -111,6 +114,11 @@ extern int nni_http_res_set_version(nni_http_res *, const char *); extern const char *nni_http_res_get_reason(nni_http_res *); extern int nni_http_res_set_reason(nni_http_res *, const char *); +// nni_http_res_is_error is true if the status was allocated as part of +// nni_http_res_alloc_error(). This is a hint to the server to replace +// the HTML body with customized content if it exists. +extern bool nni_http_res_is_error(nni_http_res *); + extern void nni_http_read(nni_http_conn *, nni_aio *); extern void nni_http_read_full(nni_http_conn *, nni_aio *); extern void nni_http_write(nni_http_conn *, nni_aio *); @@ -170,6 +178,19 @@ extern int nni_http_server_start(nni_http_server *); // associated with a callback will complete their callback, and then close. extern void nni_http_server_stop(nni_http_server *); +// nni_http_server_set_error_page sets an error page for the named status. +extern int nni_http_server_set_error_page( + nni_http_server *, uint16_t, const char *); + +// nni_http_server_set_error_page sets an error file for the named status. +extern int nni_http_server_set_error_file( + nni_http_server *, uint16_t, const char *); + +// nni_http_server_res_error takes replaces the body of the res with +// a custom error page previously set for the server, using the status +// of the res. The res must have the status set first. +extern int nni_http_server_res_error(nni_http_server *, nni_http_res *); + // nni_http_hijack is intended to be called by a handler that wishes to // take over the processing of the HTTP session -- usually to change protocols // (such as in the case of websocket). The caller is responsible for obtaining diff --git a/src/supplemental/http/http_msg.c b/src/supplemental/http/http_msg.c index bc51e408..ff9764bf 100644 --- a/src/supplemental/http/http_msg.c +++ b/src/supplemental/http/http_msg.c @@ -54,6 +54,7 @@ struct nng_http_res { char * buf; size_t bufsz; bool parsed; + bool iserr; }; static int @@ -375,6 +376,7 @@ nni_http_res_set_data(nni_http_res *res, const void *data, size_t size) if ((rv = http_set_content_length(&res->data, &res->hdrs)) != 0) { http_entity_set_data(&res->data, NULL, 0); } + res->iserr = false; return (rv); } @@ -401,9 +403,16 @@ nni_http_res_copy_data(nni_http_res *res, const void *data, size_t size) http_entity_set_data(&res->data, NULL, 0); return (rv); } + res->iserr = false; return (0); } +bool +nni_http_res_is_error(nni_http_res *res) +{ + return (res->iserr); +} + static int http_parse_header(nni_list *hdrs, void *line) { @@ -962,7 +971,7 @@ static struct { }; const char * -http_reason(uint16_t code) +nni_http_reason(uint16_t code) { for (int i = 0; http_status[i].code != 0; i++) { if (http_status[i].code == code) { @@ -975,14 +984,14 @@ http_reason(uint16_t code) const char * nni_http_res_get_reason(nni_http_res *res) { - return (res->rsn ? res->rsn : http_reason(res->code)); + return (res->rsn ? res->rsn : nni_http_reason(res->code)); } int nni_http_res_set_reason(nni_http_res *res, const char *reason) { if ((reason != NULL) && - (strcmp(reason, http_reason(res->code)) == 0)) { + (strcmp(reason, nni_http_reason(res->code)) == 0)) { reason = NULL; } return (http_set_string(&res->rsn, reason)); @@ -1009,7 +1018,7 @@ nni_http_res_alloc_error(nni_http_res **resp, uint16_t err) "<p align=\"center\">" "<span style=\"font-size: 24px; font-family: Arial, sans serif;\">" "%s</span></p></body>", - err, http_reason(err), err, http_reason(err)); + err, nni_http_reason(err), err, nni_http_reason(err)); res->code = err; if (((rv = nni_http_res_set_header( @@ -1017,7 +1026,8 @@ nni_http_res_alloc_error(nni_http_res **resp, uint16_t err) ((rv = nni_http_res_copy_data(res, html, strlen(html))) != 0)) { nni_http_res_free(res); } else { - *resp = res; + res->iserr = true; + *resp = res; } return (rv); } diff --git a/src/supplemental/http/http_public.c b/src/supplemental/http/http_public.c index 40d4a19c..94e51ed0 100644 --- a/src/supplemental/http/http_public.c +++ b/src/supplemental/http/http_public.c @@ -676,6 +676,34 @@ nng_http_server_del_handler(nng_http_server *srv, nng_http_handler *h) } int +nng_http_server_set_error_page( + nng_http_server *srv, uint16_t code, const char *body) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_server_set_error_page(srv, code, body)); +#else + NNI_ARG_UNUSED(srv); + NNI_ARG_UNUSED(code); + NNI_ARG_UNUSED(body); + return (NNG_ENOTSUP); +#endif +} + +int +nng_http_server_set_error_file( + nng_http_server *srv, uint16_t code, const char *path) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_server_set_error_file(srv, code, path)); +#else + NNI_ARG_UNUSED(srv); + NNI_ARG_UNUSED(code); + NNI_ARG_UNUSED(path); + return (NNG_ENOTSUP); +#endif +} + +int nng_http_server_set_tls(nng_http_server *srv, struct nng_tls_config *cfg) { #if defined(NNG_SUPP_HTTP) && defined(NNG_SUPP_TLS) @@ -700,6 +728,19 @@ nng_http_server_get_tls(nng_http_server *srv, struct nng_tls_config **cfgp) } int +nng_http_server_res_error(nng_http_server *srv, nng_http_res *res) +{ +#ifdef NNG_SUPP_HTTP + return (nni_http_server_res_error(srv, res)); +#else + NNI_ARG_UNUSED(srv); + NNI_ARG_UNUSED(res); + NNI_ARG_UNUSED(code); + return (NNG_ENOTSUP); +#endif +} + +int nng_http_hijack(nng_http_conn *conn) { #ifdef NNG_SUPP_HTTP diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index 5c6d1dcc..4a07d544 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -40,7 +40,7 @@ struct nng_http_handler { void (*cb)(nni_aio *); }; -typedef struct nni_http_ctx { +typedef struct http_sconn { nni_list_node node; nni_http_conn * conn; nni_http_server *server; @@ -56,6 +56,13 @@ typedef struct nni_http_ctx { nni_reap_item reap; } http_sconn; +typedef struct http_error { + nni_list_node node; + uint16_t code; + void * body; + size_t len; +} http_error; + struct nng_http_server { nng_sockaddr addr; nni_list_node node; @@ -71,6 +78,8 @@ struct nng_http_server { nni_plat_tcp_ep *tep; char * port; char * hostname; + nni_list errors; + nni_mtx errors_mtx; }; int @@ -395,13 +404,20 @@ http_sconn_error(http_sconn *sc, uint16_t err) { nni_http_res *res; - if (nni_http_res_alloc_error(&res, err) != 0) { + if (nni_http_res_alloc(&res) != 0) { + http_sconn_close(sc); + return; + } + nni_http_res_set_status(res, err); + if (nni_http_server_res_error(sc->server, res) != 0) { + nni_http_res_free(res); http_sconn_close(sc); return; } if (sc->close) { if (nni_http_res_set_header(res, "Connection", "close") != 0) { + nni_http_res_free(res); http_sconn_close(sc); } } @@ -651,6 +667,8 @@ http_sconn_cbdone(void *arg) // the HTTP header. nni_http_res_get_data(res, &data, &size); nni_http_res_set_data(res, NULL, size); + } else if (nni_http_res_is_error(res)) { + (void) nni_http_server_res_error(s, res); } nni_http_write_res(sc->conn, res, sc->txaio); } else if (sc->close) { @@ -743,6 +761,7 @@ static void http_server_fini(nni_http_server *s) { nni_http_handler *h; + http_error * epage; nni_aio_stop(s->accaio); @@ -764,6 +783,15 @@ http_server_fini(nni_http_server *s) nni_tls_config_fini(s->tls); } #endif + nni_mtx_lock(&s->errors_mtx); + while ((epage = nni_list_first(&s->errors)) != NULL) { + nni_list_remove(&s->errors, epage); + nni_free(epage->body, epage->len); + NNI_FREE_STRUCT(epage); + } + nni_mtx_unlock(&s->errors_mtx); + nni_mtx_fini(&s->errors_mtx); + nni_aio_fini(s->accaio); nni_cv_fini(&s->cv); nni_mtx_fini(&s->mtx); @@ -804,8 +832,13 @@ http_server_init(nni_http_server **serverp, const nni_url *url) } nni_mtx_init(&s->mtx); nni_cv_init(&s->cv, &s->mtx); + nni_mtx_init(&s->errors_mtx); NNI_LIST_INIT(&s->handlers, nni_http_handler, node); NNI_LIST_INIT(&s->conns, http_sconn, node); + + nni_mtx_init(&s->errors_mtx); + NNI_LIST_INIT(&s->errors, http_error, node); + if ((rv = nni_aio_init(&s->accaio, http_server_acccb, s)) != 0) { http_server_fini(s); return (rv); @@ -951,6 +984,117 @@ nni_http_server_stop(nni_http_server *s) nni_mtx_unlock(&s->mtx); } +static int +http_server_set_err(nni_http_server *s, uint16_t code, void *body, size_t len) +{ + http_error *epage; + + nni_mtx_lock(&s->errors_mtx); + NNI_LIST_FOREACH (&s->errors, epage) { + if (epage->code == code) { + break; + } + } + if (epage == NULL) { + if ((epage = NNI_ALLOC_STRUCT(epage)) == NULL) { + nni_mtx_unlock(&s->mtx); + return (NNG_ENOMEM); + } + epage->code = code; + nni_list_append(&s->errors, epage); + } + if (epage->len != 0) { + nni_free(epage->body, epage->len); + } + epage->body = body; + epage->len = len; + nni_mtx_unlock(&s->errors_mtx); + return (0); +} + +int +nni_http_server_set_error_page( + nni_http_server *s, uint16_t code, const char *html) +{ + char * body; + int rv; + size_t len; + + // We copy the content, without the trailing NUL. + len = strlen(html); + if ((body = nni_alloc(len)) == NULL) { + return (NNG_ENOMEM); + } + memcpy(body, html, len); + if ((rv = http_server_set_err(s, code, body, len)) != 0) { + nni_free(body, len); + } + return (rv); +} + +int +nni_http_server_set_error_file( + nni_http_server *s, uint16_t code, const char *path) +{ + void * body; + size_t len; + int rv; + if ((rv = nni_file_get(path, &body, &len)) != 0) { + return (rv); + } + if ((rv = http_server_set_err(s, code, body, len)) != 0) { + nni_free(body, len); + } + return (rv); +} + +int +nni_http_server_res_error(nni_http_server *s, nni_http_res *res) +{ + http_error *epage; + char * body = NULL; + size_t len; + uint16_t code = nni_http_res_get_status(res); + int rv; + char html[512]; + + nni_mtx_lock(&s->errors_mtx); + NNI_LIST_FOREACH (&s->errors, epage) { + if (epage->code == code) { + body = epage->body; + len = epage->len; + break; + } + } + if (body == NULL) { + const char *reason = nni_http_reason(code); + // very simple builtin error page + (void) snprintf(html, sizeof(html), + "<head><title>%d %s</title></head>" + "<body><p/><h1 align=\"center\">" + "<span style=\"font-size: 36px; border-radius: 5px; " + "background-color: black; color: white; padding: 7px; " + "font-family: Arial, sans serif;\">%d</span></h1>" + "<p align=\"center\">" + "<span style=\"font-size: 24px; font-family: Arial, sans " + "serif;\">" + "%s</span></p></body>", + code, reason, code, reason); + body = html; + len = strlen(body); + } + // NB: The server lock has to be held here to guard against the + // error page being tossed or changed. + if (((rv = nni_http_res_copy_data(res, body, len)) == 0) && + ((rv = nni_http_res_set_header( + res, "Content-Type", "text/html; charset=UTF-8")) == 0)) { + nni_http_res_set_status(res, code); + } + + nni_mtx_unlock(&s->errors_mtx); + return (rv); +} + int nni_http_server_add_handler(nni_http_server *s, nni_http_handler *h) { diff --git a/tests/httpserver.c b/tests/httpserver.c index 9fefe1f7..a36901f5 100644 --- a/tests/httpserver.c +++ b/tests/httpserver.c @@ -25,6 +25,7 @@ const char *doc1 = "<html><body>Someone <b>is</b> home!</body</html>"; const char *doc2 = "This is a text file."; const char *doc3 = "<html><body>This is doc number 3.</body></html>"; +const char *doc4 = "<html><body>Whoops, Errored!</body></html>"; void cleanup(void) @@ -68,8 +69,7 @@ httpdo(nng_url *url, nng_http_req *req, nng_http_res *res, void **datap, } clen = 0; - if ((nng_http_res_get_status(res) == NNG_HTTP_STATUS_OK) && - ((ptr = nng_http_res_get_header(res, "Content-Length")) != NULL)) { + if ((ptr = nng_http_res_get_header(res, "Content-Length")) != NULL) { clen = atoi(ptr); } @@ -377,7 +377,21 @@ TestMain("HTTP Server", { snprintf(fullurl, sizeof(fullurl), "%s/docs/", urlstr); So(httpget(fullurl, &data, &size, &stat, &ctype) == 0); So(stat == NNG_HTTP_STATUS_NOT_FOUND); - So(size == 0); + }); + + Convey("Custom error page works", { + char fullurl[256]; + void * data; + size_t size; + uint16_t stat; + char * ctype; + + So(nng_http_server_set_error_page(s, 404, doc4) == 0); + snprintf(fullurl, sizeof(fullurl), "%s/docs/", urlstr); + So(httpget(fullurl, &data, &size, &stat, &ctype) == 0); + So(stat == NNG_HTTP_STATUS_NOT_FOUND); + So(size == strlen(doc4)); + So(memcmp(data, doc4, size) == 0); }); Convey("Bad method gives 405", { @@ -397,7 +411,6 @@ TestMain("HTTP Server", { So(httpdo(curl, req, res, &data, &size) == 0); So(nng_http_res_get_status(res) == NNG_HTTP_STATUS_METHOD_NOT_ALLOWED); - So(size == 0); nng_http_req_free(req); nng_http_res_free(res); nng_url_free(curl); @@ -419,7 +432,6 @@ TestMain("HTTP Server", { So(httpdo(curl, req, res, &data, &size) == 0); So(nng_http_res_get_status(res) == NNG_HTTP_STATUS_HTTP_VERSION_NOT_SUPP); - So(size == 0); nng_http_req_free(req); nng_http_res_free(res); nng_url_free(curl); @@ -441,7 +453,6 @@ TestMain("HTTP Server", { So(httpdo(curl, req, res, &data, &size) == 0); So(nng_http_res_get_status(res) == NNG_HTTP_STATUS_BAD_REQUEST); - So(size == 0); nng_http_req_free(req); nng_http_res_free(res); nng_url_free(curl); |
