diff --git a/mongoose.c b/mongoose.c index c421938bde9c145cf9a46b6e8b50a4327d4676a0..bf88c32fcde97a7e99d33f706bf1dc87dcf58d9f 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1602,16 +1602,15 @@ static void write_chunk(struct connection *conn, const char *buf, int len) { ns_send(conn->ns_conn, "\r\n", 2); } -int mg_printf(struct mg_connection *conn, const char *fmt, ...) { +size_t mg_printf(struct mg_connection *conn, const char *fmt, ...) { struct connection *c = MG_CONN_2_CONN(conn); - int len; va_list ap; va_start(ap, fmt); - len = ns_vprintf(c->ns_conn, fmt, ap); + ns_vprintf(c->ns_conn, fmt, ap); va_end(ap); - return len; + return c->ns_conn->send_iobuf.len; } static void ns_forward(struct ns_connection *from, struct ns_connection *to) { @@ -2176,7 +2175,7 @@ static int parse_http_message(char *buf, int len, struct mg_connection *ri) { n = (int) strlen(ri->uri); mg_url_decode(ri->uri, n, (char *) ri->uri, n + 1, 0); if (*ri->uri == '/' || *ri->uri == '.') { - remove_double_dots_and_double_slashes((char *) ri->uri); + remove_double_dots_and_double_slashes((char *) ri->uri); } } @@ -2376,9 +2375,10 @@ static int should_keep_alive(const struct mg_connection *conn) { (header == NULL && http_version && !strcmp(http_version, "1.1"))); } -int mg_write(struct mg_connection *c, const void *buf, int len) { +size_t mg_write(struct mg_connection *c, const void *buf, int len) { struct connection *conn = MG_CONN_2_CONN(c); - return ns_send(conn->ns_conn, buf, len); + ns_send(conn->ns_conn, buf, len); + return conn->ns_conn->send_iobuf.len; } void mg_send_status(struct mg_connection *c, int status) { @@ -2405,12 +2405,14 @@ static void terminate_headers(struct mg_connection *c) { } } -void mg_send_data(struct mg_connection *c, const void *data, int data_len) { +size_t mg_send_data(struct mg_connection *c, const void *data, int data_len) { + struct connection *conn = MG_CONN_2_CONN(c); terminate_headers(c); write_chunk(MG_CONN_2_CONN(c), (const char *) data, data_len); + return conn->ns_conn->send_iobuf.len; } -void mg_printf_data(struct mg_connection *c, const char *fmt, ...) { +size_t mg_printf_data(struct mg_connection *c, const char *fmt, ...) { struct connection *conn = MG_CONN_2_CONN(c); va_list ap; int len; @@ -2428,6 +2430,7 @@ void mg_printf_data(struct mg_connection *c, const char *fmt, ...) { if (buf != mem && buf != NULL) { free(buf); } + return conn->ns_conn->send_iobuf.len; } #if !defined(MONGOOSE_NO_WEBSOCKET) || !defined(MONGOOSE_NO_AUTH) @@ -2660,15 +2663,14 @@ static int deliver_websocket_frame(struct connection *conn) { return buffered; } -int mg_websocket_write(struct mg_connection* conn, int opcode, +size_t mg_websocket_write(struct mg_connection* conn, int opcode, const char *data, size_t data_len) { unsigned char mem[4192], *copy = mem; size_t copy_len = 0; - int retval = -1; if (data_len + 10 > sizeof(mem) && (copy = (unsigned char *) malloc(data_len + 10)) == NULL) { - return -1; + return 0; } copy[0] = 0x80 + (opcode & 0x0f); @@ -2696,17 +2698,17 @@ int mg_websocket_write(struct mg_connection* conn, int opcode, } if (copy_len > 0) { - retval = mg_write(conn, copy, copy_len); + mg_write(conn, copy, copy_len); } if (copy != mem) { free(copy); } - return retval; + return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len; } -int mg_websocket_printf(struct mg_connection* conn, int opcode, - const char *fmt, ...) { +size_t mg_websocket_printf(struct mg_connection* conn, int opcode, + const char *fmt, ...) { char mem[4192], *buf = mem; va_list ap; int len; @@ -2721,7 +2723,7 @@ int mg_websocket_printf(struct mg_connection* conn, int opcode, free(buf); } - return len; + return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len; } static void send_websocket_handshake_if_requested(struct mg_connection *conn) { @@ -4121,8 +4123,9 @@ static void proxify_connection(struct connection *conn) { } } -static void open_local_endpoint(struct connection *conn, int skip_user) { #ifndef MONGOOSE_NO_FILESYSTEM +void mg_send_file(struct mg_connection *c, const char *file_name) { + struct connection *conn = MG_CONN_2_CONN(c); file_stat_t st; char path[MAX_PATH_SIZE]; int exists = 0, is_directory = 0; @@ -4136,7 +4139,57 @@ static void open_local_endpoint(struct connection *conn, int skip_user) { #else const char *dir_lst = "yes"; #endif + + mg_snprintf(path, sizeof(path), "%s", file_name); + exists = stat(path, &st) == 0; + is_directory = S_ISDIR(st.st_mode); + + if (!exists || must_hide_file(conn, path)) { + send_http_error(conn, 404, NULL); + } else if (is_directory && + conn->mg_conn.uri[strlen(conn->mg_conn.uri) - 1] != '/') { + conn->mg_conn.status_code = 301; + mg_printf(&conn->mg_conn, "HTTP/1.1 301 Moved Permanently\r\n" + "Location: %s/\r\n\r\n", conn->mg_conn.uri); + close_local_endpoint(conn); + } else if (is_directory && !find_index_file(conn, path, sizeof(path), &st)) { + if (!mg_strcasecmp(dir_lst, "yes")) { +#ifndef MONGOOSE_NO_DIRECTORY_LISTING + send_directory_listing(conn, path); +#else + send_http_error(conn, 501, NULL); +#endif + } else { + send_http_error(conn, 403, NULL); + } + } else if (mg_match_prefix(cgi_pat, strlen(cgi_pat), path) > 0) { +#if !defined(MONGOOSE_NO_CGI) + open_cgi_endpoint(conn, path); +#else + send_http_error(conn, 501, NULL); +#endif // !MONGOOSE_NO_CGI +#ifndef MONGOOSE_NO_SSI + } else if (mg_match_prefix(conn->server->config_options[SSI_PATTERN], + strlen(conn->server->config_options[SSI_PATTERN]), + path) > 0) { + handle_ssi_request(conn, path); #endif + } else if (is_not_modified(conn, &st)) { + send_http_error(conn, 304, NULL); + } else if ((conn->endpoint.fd = open(path, O_RDONLY | O_BINARY)) != -1) { + // O_BINARY is required for Windows, otherwise in default text mode + // two bytes \r\n will be read as one. + open_file_endpoint(conn, path, &st); + } else { + send_http_error(conn, 404, NULL); + } +} +#endif // !MONGOOSE_NO_FILESYSTEM + +static void open_local_endpoint(struct connection *conn, int skip_user) { + char path[MAX_PATH_SIZE]; + file_stat_t st; + int exists = 0; // If EP_USER was set in a prev call, reset it conn->endpoint_type = EP_NONE; @@ -4170,16 +4223,16 @@ static void open_local_endpoint(struct connection *conn, int skip_user) { proxify_connection(conn); return; } - -#ifdef MONGOOSE_NO_FILESYSTEM + if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) { send_options(conn); - } else { - send_http_error(conn, 404, NULL); + return; } + +#ifdef MONGOOSE_NO_FILESYSTEM + send_http_error(conn, 404, NULL); #else exists = convert_uri_to_file_name(conn, path, sizeof(path), &st); - is_directory = S_ISDIR(st.st_mode); if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) { send_options(conn); @@ -4201,44 +4254,8 @@ static void open_local_endpoint(struct connection *conn, int skip_user) { } else if (!strcmp(conn->mg_conn.request_method, "PUT")) { handle_put(conn, path); #endif - } else if (!exists || must_hide_file(conn, path)) { - send_http_error(conn, 404, NULL); - } else if (is_directory && - conn->mg_conn.uri[strlen(conn->mg_conn.uri) - 1] != '/') { - conn->mg_conn.status_code = 301; - mg_printf(&conn->mg_conn, "HTTP/1.1 301 Moved Permanently\r\n" - "Location: %s/\r\n\r\n", conn->mg_conn.uri); - close_local_endpoint(conn); - } else if (is_directory && !find_index_file(conn, path, sizeof(path), &st)) { - if (!mg_strcasecmp(dir_lst, "yes")) { -#ifndef MONGOOSE_NO_DIRECTORY_LISTING - send_directory_listing(conn, path); -#else - send_http_error(conn, 501, NULL); -#endif - } else { - send_http_error(conn, 403, NULL); - } - } else if (mg_match_prefix(cgi_pat, strlen(cgi_pat), path) > 0) { -#if !defined(MONGOOSE_NO_CGI) - open_cgi_endpoint(conn, path); -#else - send_http_error(conn, 501, NULL); -#endif // !MONGOOSE_NO_CGI -#ifndef MONGOOSE_NO_SSI - } else if (mg_match_prefix(conn->server->config_options[SSI_PATTERN], - strlen(conn->server->config_options[SSI_PATTERN]), - path) > 0) { - handle_ssi_request(conn, path); -#endif - } else if (is_not_modified(conn, &st)) { - send_http_error(conn, 304, NULL); - } else if ((conn->endpoint.fd = open(path, O_RDONLY | O_BINARY)) != -1) { - // O_BINARY is required for Windows, otherwise in default text mode - // two bytes \r\n will be read as one. - open_file_endpoint(conn, path, &st); } else { - send_http_error(conn, 404, NULL); + mg_send_file(&conn->mg_conn, path); } #endif // MONGOOSE_NO_FILESYSTEM } diff --git a/mongoose.h b/mongoose.h index 18afc2ff7adb03a9f82495f892f3f01e712bd74e..fc431886da4c283f71823d7a9b8664e7028604fd 100644 --- a/mongoose.h +++ b/mongoose.h @@ -99,17 +99,15 @@ struct mg_connection *mg_connect(struct mg_server *, const char *, int, int); // Connection management functions void mg_send_status(struct mg_connection *, int status_code); void mg_send_header(struct mg_connection *, const char *name, const char *val); -void mg_send_data(struct mg_connection *, const void *data, int data_len); -void mg_printf_data(struct mg_connection *, const char *format, ...); +size_t mg_send_data(struct mg_connection *, const void *data, int data_len); +size_t mg_printf_data(struct mg_connection *, const char *format, ...); +size_t mg_write(struct mg_connection *, const void *buf, int len); +size_t mg_printf(struct mg_connection *conn, const char *fmt, ...); -int mg_websocket_write(struct mg_connection *, int opcode, - const char *data, size_t data_len); -int mg_websocket_printf(struct mg_connection* conn, int opcode, - const char *fmt, ...); - -// Deprecated in favor of mg_send_* interface -int mg_write(struct mg_connection *, const void *buf, int len); -int mg_printf(struct mg_connection *conn, const char *fmt, ...); +size_t mg_websocket_write(struct mg_connection *, int opcode, + const char *data, size_t data_len); +size_t mg_websocket_printf(struct mg_connection* conn, int opcode, + const char *fmt, ...); const char *mg_get_header(const struct mg_connection *, const char *name); const char *mg_get_mime_type(const char *name, const char *default_mime_type); @@ -122,6 +120,7 @@ int mg_parse_multipart(const char *buf, int buf_len, const char **data, int *data_len); // Utility functions +void mg_send_file(struct mg_connection *, const char *path); void *mg_start_thread(void *(*func)(void *), void *param); char *mg_md5(char buf[33], ...); int mg_authorize_digest(struct mg_connection *c, FILE *fp);