diff --git a/docs/c-api/http_server.h/intro.md b/docs/c-api/http_server.h/intro.md index 0879399c74a79dda6f532b0ebc7da84454e529c2..bfa6d7a3e69768947182302d7e1802ff8174c7a3 100644 --- a/docs/c-api/http_server.h/intro.md +++ b/docs/c-api/http_server.h/intro.md @@ -16,6 +16,7 @@ items: - { name: mg_send_http_chunk.md } - { name: mg_printf_http_chunk.md } - { name: mg_send_response_line.md } + - { name: mg_http_send_redirect.md } - { name: mg_send_head.md } - { name: mg_printf_html_escape.md } - { name: mg_fu_fname_fn.md } diff --git a/docs/c-api/http_server.h/mg_http_send_redirect.md b/docs/c-api/http_server.h/mg_http_send_redirect.md new file mode 100644 index 0000000000000000000000000000000000000000..206f3e9de7e0f905bc2bbdb5b4441dfd39693dd5 --- /dev/null +++ b/docs/c-api/http_server.h/mg_http_send_redirect.md @@ -0,0 +1,24 @@ +--- +title: "mg_http_send_redirect()" +decl_name: "mg_http_send_redirect" +symbol_kind: "func" +signature: | + void mg_http_send_redirect(struct mg_connection *nc, int status_code, + const struct mg_str location, + const struct mg_str extra_headers); +--- + +Sends a redirect response. +`status_code` should be either 301 or 302 and `location` point to the +new location. +If `extra_headers` is not empty, then `extra_headers` are also sent +after the reponse line. `extra_headers` must NOT end end with new line. +Example: + + mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *"); + +Will result in: + + HTTP/1.1 200 OK\r\n + Access-Control-Allow-Origin: *\r\n + diff --git a/docs/c-api/http_server.h/mg_send_response_line.md b/docs/c-api/http_server.h/mg_send_response_line.md index 213927dd53a802cc82f9ad61962b04bc082b254e..4bd22639a2649e2310a2fd387d3b272c668c07df 100644 --- a/docs/c-api/http_server.h/mg_send_response_line.md +++ b/docs/c-api/http_server.h/mg_send_response_line.md @@ -3,7 +3,7 @@ title: "mg_send_response_line()" decl_name: "mg_send_response_line" symbol_kind: "func" signature: | - void mg_send_response_line(struct mg_connection *c, int status_code, + void mg_send_response_line(struct mg_connection *nc, int status_code, const char *extra_headers); --- diff --git a/docs/c-api/util.h/intro.md b/docs/c-api/util.h/intro.md index 2d8024a0536755fe2f1bda0c901c09fe32fa9708..88b8afbc86c3b8763fff0a7b5c3d895c6621cdfe 100644 --- a/docs/c-api/util.h/intro.md +++ b/docs/c-api/util.h/intro.md @@ -17,6 +17,7 @@ items: - { name: mg_sock_addr_to_str.md } - { name: mg_hexdump.md } - { name: mg_hexdump_connection.md } + - { name: mg_asprintf.md } - { name: mg_avprintf.md } - { name: mg_is_big_endian.md } - { name: mg_next_comma_list_entry.md } diff --git a/docs/c-api/util.h/mg_asprintf.md b/docs/c-api/util.h/mg_asprintf.md new file mode 100644 index 0000000000000000000000000000000000000000..10dd17460336384aa6903ca58883585484d45e10 --- /dev/null +++ b/docs/c-api/util.h/mg_asprintf.md @@ -0,0 +1,22 @@ +--- +title: "mg_asprintf()" +decl_name: "mg_asprintf" +symbol_kind: "func" +signature: | + int mg_asprintf(char **buf, size_t size, const char *fmt, ...); +--- + +Prints message to the buffer. If the buffer is large enough to hold the +message, it returns buffer. If buffer is to small, it allocates a large +enough buffer on heap and returns allocated buffer. +This is a supposed use case: + + char buf[5], *p = buf; + mg_avprintf(&p, sizeof(buf), "%s", "hi there"); + use_p_somehow(p); + if (p != buf) { + free(p); + } + +The purpose of this is to avoid malloc-ing if generated strings are small. + diff --git a/docs/c-api/util.h/mg_avprintf.md b/docs/c-api/util.h/mg_avprintf.md index 9a70d8400685982c3b7dd3bdcf99391d4afd43ea..aff55db0126f1d5b6b49ab302616f64ae64e1144 100644 --- a/docs/c-api/util.h/mg_avprintf.md +++ b/docs/c-api/util.h/mg_avprintf.md @@ -6,17 +6,5 @@ signature: | int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); --- -Prints message to the buffer. If the buffer is large enough to hold the -message, it returns buffer. If buffer is to small, it allocates a large -enough buffer on heap and returns allocated buffer. -This is a supposed use case: - - char buf[5], *p = buf; - p = mg_avprintf(&p, sizeof(buf), "%s", "hi there"); - use_p_somehow(p); - if (p != buf) { - free(p); - } - -The purpose of this is to avoid malloc-ing if generated strings are small. +Same as mg_asprintf, but takes varargs list. diff --git a/examples/connected_device_2/server.c b/examples/connected_device_2/server.c index 37281c5bf8f8f81c514baaf8d3ec8b8c0ac2d15f..26bf30924394ae5c11cf97e9bc186d17bd826983 100644 --- a/examples/connected_device_2/server.c +++ b/examples/connected_device_2/server.c @@ -20,7 +20,7 @@ static void handle_save(struct mg_connection *nc, struct http_message *hm) { sizeof(s_settings.setting2)); // Send response - mg_printf(nc, "%s", "HTTP/1.1 302 OK\r\nLocation: /\r\n\r\n"); + mg_http_send_redirect(nc, 302, mg_mk_str("/"), mg_mk_str(NULL)); } static void handle_ssi_call(struct mg_connection *nc, const char *param) { diff --git a/examples/connected_device_3/server.c b/examples/connected_device_3/server.c index fc9f907db7cd1ceeb34c481d00332aa54814770a..d939716acc2211f7303c31fe2f2805ef66c9d40b 100644 --- a/examples/connected_device_3/server.c +++ b/examples/connected_device_3/server.c @@ -20,7 +20,7 @@ static void handle_save(struct mg_connection *nc, struct http_message *hm) { sizeof(s_settings.setting2)); // Send response - mg_printf(nc, "%s", "HTTP/1.1 302 OK\r\nLocation: /\r\n\r\n"); + mg_http_send_redirect(nc, 302, mg_mk_str("/"), mg_mk_str(NULL)); } static void handle_get_cpu_usage(struct mg_connection *nc) { diff --git a/examples/connected_device_4/server.c b/examples/connected_device_4/server.c index f836203d4316e0298c656c7abe5f28966a115a24..854aa13be2e16efb35eb1421eff691df0aa03e44 100644 --- a/examples/connected_device_4/server.c +++ b/examples/connected_device_4/server.c @@ -20,7 +20,7 @@ static void handle_save(struct mg_connection *nc, struct http_message *hm) { sizeof(s_settings.setting2)); // Send response - mg_printf(nc, "%s", "HTTP/1.1 302 OK\r\nLocation: /\r\n\r\n"); + mg_http_send_redirect(nc, 302, mg_mk_str("/"), mg_mk_str(NULL)); } static void handle_get_cpu_usage(struct mg_connection *nc) { diff --git a/examples/cookie_auth/cookie_auth.c b/examples/cookie_auth/cookie_auth.c index 2c0811237a56fc78e95237942040801246f12d99..d0bc672ce8198e191ea5d168c696c6d48cdda354 100644 --- a/examples/cookie_auth/cookie_auth.c +++ b/examples/cookie_auth/cookie_auth.c @@ -120,12 +120,6 @@ static struct session *create_session(const char *user, return s; } -static void set_session_cookie(struct mg_connection *nc, - const struct session *s) { - mg_printf(nc, "Set-Cookie: %s=%" INT64_X_FMT "; path=/\r\n", - SESSION_COOKIE_NAME, s->id); -} - /* * If requested via GET, serves the login page. * If requested via POST (form submission), checks password and logs user in. @@ -143,10 +137,11 @@ static void login_handler(struct mg_connection *nc, int ev, void *p) { if (ul > 0 && pl > 0) { if (check_pass(user, pass)) { struct session *s = create_session(user, hm); - mg_printf(nc, "HTTP/1.0 302 Found\r\n"); - set_session_cookie(nc, s); - mg_printf(nc, "Location: /\r\n"); - mg_printf(nc, "\r\nHello, %s!\r\n", s->user); + char shead[100]; + snprintf(shead, sizeof(shead), + "Set-Cookie: %s=%" INT64_X_FMT "; path=/", SESSION_COOKIE_NAME, + s->id); + mg_http_send_redirect(nc, 302, mg_mk_str("/"), mg_mk_str(shead)); fprintf(stderr, "%s logged in, sid %" INT64_X_FMT "\n", s->user, s->id); } else { mg_printf(nc, "HTTP/1.0 403 Unauthorized\r\n\r\nWrong password.\r\n"); @@ -165,13 +160,9 @@ static void login_handler(struct mg_connection *nc, int ev, void *p) { */ static void logout_handler(struct mg_connection *nc, int ev, void *p) { struct http_message *hm = (struct http_message *) p; - mg_printf(nc, - "HTTP/1.0 302 Found\r\n" - "Set-Cookie: %s=\r\n" - "Location: /\r\n" - "\r\n" - "Logged out", - SESSION_COOKIE_NAME); + char shead[100]; + snprintf(shead, sizeof(shead), "Set-Cookie: %s=", SESSION_COOKIE_NAME); + mg_http_send_redirect(nc, 302, mg_mk_str("/"), mg_mk_str(shead)); struct session *s = get_session(hm); if (s != NULL) { fprintf(stderr, "%s logged out, session %" INT64_X_FMT " destroyed\n", @@ -203,11 +194,8 @@ static void ev_handler(struct mg_connection *nc, int ev, void *p) { struct session *s = get_session(hm); /* Ask the user to log in if they did not present a valid cookie. */ if (s == NULL) { - mg_printf(nc, - "HTTP/1.0 302 Found\r\n" - "Location: /login.html\r\n" - "\r\n" - "Please log in"); + mg_http_send_redirect(nc, 302, mg_mk_str("/login.html"), + mg_mk_str(NULL)); nc->flags |= MG_F_SEND_AND_CLOSE; break; } diff --git a/mongoose.c b/mongoose.c index 94b7227962699f05e60400bd9ce8003a606aa45b..111930bfd2101d4828c90dd28865ae46f55c10d9 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5336,6 +5336,28 @@ void mg_send_response_line(struct mg_connection *nc, int status_code, mg_send_response_line_s(nc, status_code, mg_mk_str(extra_headers)); } +void mg_http_send_redirect(struct mg_connection *nc, int status_code, + const struct mg_str location, + const struct mg_str extra_headers) { + char bbody[100], *pbody = bbody; + int bl = mg_asprintf(&pbody, sizeof(bbody), + "<p>Moved <a href='%.*s'>here</a>.\r\n", + (int) location.len, location.p); + char bhead[150], *phead = bhead; + mg_asprintf(&phead, sizeof(bhead), + "Location: %.*s\r\n" + "Content-Type: text/html\r\n" + "Content-Length: %d\r\n" + "Cache-Control: no-cache\r\n" + "%.*s%s", + (int) location.len, location.p, bl, (int) extra_headers.len, + extra_headers.p, (extra_headers.len > 0 ? "\r\n" : "")); + mg_send_response_line(nc, status_code, phead); + if (phead != bhead) MG_FREE(phead); + mg_send(nc, pbody, bl); + if (pbody != bbody) MG_FREE(pbody); +} + void mg_send_head(struct mg_connection *c, int status_code, int64_t content_length, const char *extra_headers) { mg_send_response_line(c, status_code, extra_headers); @@ -7754,6 +7776,15 @@ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap) { return len; } +int mg_asprintf(char **buf, size_t size, const char *fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = mg_avprintf(buf, size, fmt, ap); + va_end(ap); + return ret; +} + #if !defined(MG_DISABLE_HEXDUMP) void mg_hexdump_connection(struct mg_connection *nc, const char *path, const void *buf, int num_bytes, int ev) { diff --git a/mongoose.h b/mongoose.h index 37dd0572480ec8d8e83a59fff090b466da10cf12..825a7cf0ca5d350d5fb9fed3026fe2a4c51935cc 100644 --- a/mongoose.h +++ b/mongoose.h @@ -2009,6 +2009,7 @@ int mg_hexdump(const void *buf, int len, char *dst, int dst_len); */ void mg_hexdump_connection(struct mg_connection *nc, const char *path, const void *buf, int num_bytes, int ev); + /* * Prints message to the buffer. If the buffer is large enough to hold the * message, it returns buffer. If buffer is to small, it allocates a large @@ -2016,7 +2017,7 @@ void mg_hexdump_connection(struct mg_connection *nc, const char *path, * This is a supposed use case: * * char buf[5], *p = buf; - * p = mg_avprintf(&p, sizeof(buf), "%s", "hi there"); + * mg_avprintf(&p, sizeof(buf), "%s", "hi there"); * use_p_somehow(p); * if (p != buf) { * free(p); @@ -2024,6 +2025,9 @@ void mg_hexdump_connection(struct mg_connection *nc, const char *path, * * The purpose of this is to avoid malloc-ing if generated strings are small. */ +int mg_asprintf(char **buf, size_t size, const char *fmt, ...); + +/* Same as mg_asprintf, but takes varargs list. */ int mg_avprintf(char **buf, size_t size, const char *fmt, va_list ap); /* @@ -2800,9 +2804,28 @@ void mg_printf_http_chunk(struct mg_connection *nc, const char *fmt, ...); * HTTP/1.1 200 OK\r\n * Access-Control-Allow-Origin: *\r\n */ -void mg_send_response_line(struct mg_connection *c, int status_code, +void mg_send_response_line(struct mg_connection *nc, int status_code, const char *extra_headers); +/* + * Sends a redirect response. + * `status_code` should be either 301 or 302 and `location` point to the + * new location. + * If `extra_headers` is not empty, then `extra_headers` are also sent + * after the reponse line. `extra_headers` must NOT end end with new line. + * Example: + * + * mg_send_response_line(nc, 200, "Access-Control-Allow-Origin: *"); + * + * Will result in: + * + * HTTP/1.1 200 OK\r\n + * Access-Control-Allow-Origin: *\r\n + */ +void mg_http_send_redirect(struct mg_connection *nc, int status_code, + const struct mg_str location, + const struct mg_str extra_headers); + /* * Sends the response line and headers. * This function sends the response line with the `status_code`, and