diff options
Diffstat (limited to 'src/supplemental/http/http_server.c')
| -rw-r--r-- | src/supplemental/http/http_server.c | 179 |
1 files changed, 141 insertions, 38 deletions
diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c index 1a7f2c25..44c338f4 100644 --- a/src/supplemental/http/http_server.c +++ b/src/supplemental/http/http_server.c @@ -229,12 +229,8 @@ http_sconn_reap(void *arg) if (sc->conn != NULL) { nni_http_conn_fini(sc->conn); } - if (sc->req != NULL) { - nni_http_req_free(sc->req); - } - if (sc->res != NULL) { - nni_http_res_free(sc->res); - } + nni_http_req_free(sc->req); + nni_http_res_free(sc->res); nni_aio_fini(sc->rxaio); nni_aio_fini(sc->txaio); nni_aio_fini(sc->txdataio); @@ -294,10 +290,8 @@ http_sconn_txdatdone(void *arg) return; } - if (sc->res != NULL) { - nni_http_res_free(sc->res); - sc->res = NULL; - } + nni_http_res_free(sc->res); + sc->res = NULL; if (sc->close) { http_sconn_close(sc); @@ -325,10 +319,8 @@ http_sconn_txdone(void *arg) return; } - if (sc->res != NULL) { - nni_http_res_free(sc->res); - sc->res = NULL; - } + nni_http_res_free(sc->res); + sc->res = NULL; sc->handler = NULL; nni_http_req_reset(sc->req); nni_http_read_req(sc->conn, sc->req, sc->rxaio); @@ -1089,10 +1081,10 @@ nni_http_server_res_error(nni_http_server *s, nni_http_res *res) { http_error *epage; char * body = NULL; + char * html = 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) { @@ -1102,23 +1094,16 @@ nni_http_server_res_error(nni_http_server *s, nni_http_res *res) break; } } + nni_mtx_unlock(&s->errors_mtx); + 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); + if ((rv = nni_http_alloc_html_error(&html, code, NULL)) != 0) { + return (rv); + } 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) && @@ -1126,8 +1111,8 @@ nni_http_server_res_error(nni_http_server *s, nni_http_res *res) res, "Content-Type", "text/html; charset=UTF-8")) == 0)) { nni_http_res_set_status(res, code); } + nni_strfree(html); - nni_mtx_unlock(&s->errors_mtx); return (rv); } @@ -1335,9 +1320,7 @@ http_handle_file(nni_aio *aio) ((rv = nni_http_res_set_header(res, "Content-Type", ctype)) != 0) || ((rv = nni_http_res_copy_data(res, data, size)) != 0)) { - if (res != NULL) { - nni_http_res_free(res); - } + nni_http_res_free(res); nni_free(data, size); nni_aio_finish_error(aio, rv); return; @@ -1526,9 +1509,7 @@ http_handle_dir(nni_aio *aio) ((rv = nni_http_res_set_header(res, "Content-Type", ctype)) != 0) || ((rv = nni_http_res_copy_data(res, data, size)) != 0)) { - if (res != NULL) { - nni_http_res_free(res); - } + nni_http_res_free(res); nni_free(data, size); nni_aio_finish_error(aio, rv); return; @@ -1573,6 +1554,130 @@ nni_http_handler_init_directory( return (0); } +typedef struct http_redirect { + uint16_t code; + char * where; +} http_redirect; + +static void +http_handle_redirect(nni_aio *aio) +{ + nni_http_res * r = NULL; + char * html = NULL; + char * msg = NULL; + char * loc = NULL; + http_redirect * hr; + nni_http_handler *h; + int rv; + nni_http_req * req; + const char * base; + const char * uri; + + req = nni_aio_get_input(aio, 0); + h = nni_aio_get_input(aio, 1); + base = nni_http_handler_get_uri(h); // base uri + uri = nni_http_req_get_uri(req); + + hr = nni_http_handler_get_data(h); + + // If we are doing a full tree, then include the entire suffix. + if (strncmp(uri, base, strlen(base)) == 0) { + rv = nni_asprintf(&loc, "%s%s", hr->where, uri + strlen(base)); + if (rv != 0) { + nni_aio_finish_error(aio, rv); + return; + } + } else { + loc = hr->where; + } + + // Builtin redirect page + rv = nni_asprintf(&msg, + "You should be automatically redirected to <a href=\"%s\">%s</a>.", + loc, loc); + + // Build a response. We always close the connection for redirects, + // because it is probably going to another server. This also + // keeps us from having to consume the entity body, we can just + // discard it. + if ((rv != 0) || ((rv = nni_http_res_alloc(&r)) != 0) || + ((rv = nni_http_alloc_html_error(&html, hr->code, msg)) != 0) || + ((rv = nni_http_res_set_status(r, hr->code)) != 0) || + ((rv = nni_http_res_set_header(r, "Connection", "close")) != 0) || + ((rv = nni_http_res_set_header( + r, "Content-Type", "text/html; charset=UTF-8")) != 0) || + ((rv = nni_http_res_set_header(r, "Location", loc)) != 0) || + ((rv = nni_http_res_copy_data(r, html, strlen(html))) != 0)) { + if (loc != hr->where) { + nni_strfree(loc); + } + nni_strfree(msg); + nni_strfree(html); + nni_http_res_free(r); + nni_aio_finish_error(aio, rv); + return; + } + if (loc != hr->where) { + nni_strfree(loc); + } + nni_strfree(msg); + nni_strfree(html); + nni_aio_set_output(aio, 0, r); + nni_aio_finish(aio, 0, 0); +} + +static void +http_redirect_free(void *arg) +{ + http_redirect *hr; + + if ((hr = arg) != NULL) { + nni_strfree(hr->where); + NNI_FREE_STRUCT(hr); + } +} + +int +nni_http_handler_init_redirect(nni_http_handler **hpp, const char *uri, + uint16_t status, const char *where) +{ + nni_http_handler *h; + int rv; + http_redirect * hr; + + if ((hr = NNI_ALLOC_STRUCT(hr)) == NULL) { + return (NNG_ENOMEM); + } + if ((hr->where = nni_strdup(where)) == NULL) { + NNI_FREE_STRUCT(hr); + return (NNG_ENOMEM); + } + if (status == 0) { + status = NNG_HTTP_STATUS_STATUS_MOVED_PERMANENTLY; + } + hr->code = status; + + if ((rv = nni_http_handler_init(&h, uri, http_handle_redirect)) != 0) { + http_redirect_free(hr); + return (rv); + } + + if (((rv = nni_http_handler_set_method(h, NULL)) != 0) || + ((rv = nni_http_handler_set_data(h, hr, http_redirect_free)) != + 0)) { + http_redirect_free(hr); + nni_http_handler_fini(h); + return (rv); + } + + // We don't need to collect the body at all, because the handler + // just discards the content and closes the connection. + nni_http_handler_collect_body(h, false, 0); + + *hpp = h; + return (0); +} + typedef struct http_static { void * data; size_t size; @@ -1599,9 +1704,7 @@ http_handle_static(nni_aio *aio) ((rv = nni_http_res_set_header(r, "Content-Type", ctype)) != 0) || ((rv = nni_http_res_set_status(r, NNG_HTTP_STATUS_OK)) != 0) || ((rv = nni_http_res_set_data(r, hs->data, hs->size)) != 0)) { - if (r != NULL) { - nni_http_res_free(r); - } + nni_http_res_free(r); nni_aio_finish_error(aio, rv); return; } |
