From aee04413efd0958dda6b65059da45e1a2825f174 Mon Sep 17 00:00:00 2001 From: Lammert Bies Date: Sat, 10 Dec 2016 21:53:02 +0100 Subject: [PATCH] Moved handle_propfind to own file --- Makefile | 1 + src/httplib_handle_propfind.c | 134 ++++++++++++++++++++++++++++++++++ src/libhttp-private.h | 10 +++ src/libhttp.c | 109 ++++----------------------- 4 files changed, 158 insertions(+), 96 deletions(-) create mode 100644 src/httplib_handle_propfind.c diff --git a/Makefile b/Makefile index 2ecdeb82..85d8296b 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,7 @@ LIB_SOURCES = src/libhttp.c \ src/httplib_getreq.c \ src/httplib_handle_file_based_request.c \ src/httplib_handle_form_request.c \ + src/httplib_handle_propfind.c \ src/httplib_handle_request.c \ src/httplib_handle_websocket_request.c \ src/httplib_initialize_ssl.c \ diff --git a/src/httplib_handle_propfind.c b/src/httplib_handle_propfind.c new file mode 100644 index 00000000..62068c27 --- /dev/null +++ b/src/httplib_handle_propfind.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2016 Lammert Bies + * Copyright (c) 2013-2016 the Civetweb developers + * Copyright (c) 2004-2013 Sergey Lyubka + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + + +#include "libhttp-private.h" + + + +#if !defined(NO_FILES) + +/* + * static void print_props( struct mg_connection *conn, const char *uri, struct file *filep ); + * + * The function print_props() writes the PROPFIND properties for a collection + * event. + */ + +static void print_props( struct mg_connection *conn, const char *uri, struct file *filep ) { + + char mtime[64]; + + if ( conn == NULL || uri == NULL || filep == NULL ) return; + + XX_httplib_gmt_time_string(mtime, sizeof(mtime), &filep->last_modified); + conn->num_bytes_sent += + mg_printf(conn, + "" + "%s" + "" + "" + "%s" + "%" INT64_FMT "" + "%s" + "" + "HTTP/1.1 200 OK" + "" + "\n", + uri, + filep->is_directory ? "" : "", + filep->size, + mtime); + +} /* print_props */ + + + +/* + * static void print_dav_dir_entry( struct de *de, void *data ); + * + * The function print_dav_dir_entry() is used to send the properties of a + * webdav directory to the remote client. + */ + +static void print_dav_dir_entry( struct de *de, void *data ) { + + char href[PATH_MAX]; + char href_encoded[PATH_MAX * 3 /* worst case */]; + int truncated; + + struct mg_connection *conn = (struct mg_connection *)data; + if (!de || !conn) return; + + XX_httplib_snprintf(conn, &truncated, href, sizeof(href), "%s%s", conn->request_info.local_uri, de->file_name); + + if (!truncated) { + mg_url_encode(href, href_encoded, PATH_MAX * 3); + print_props(conn, href_encoded, &de->file); + } + +} /* print_dav_dir_entry */ + + + +/* + * void XX_httplib_handle_propfind( struct mg_connection *conn, const char *path, struct file *filep ); + * + * The function XX_httlib_handle_propfind() handles a propfind request. + */ + +void XX_httplib_handle_propfind( struct mg_connection *conn, const char *path, struct file *filep ) { + + const char *depth = mg_get_header(conn, "Depth"); + char date[64]; + time_t curtime = time(NULL); + + XX_httplib_gmt_time_string(date, sizeof(date), &curtime); + + if (!conn || !path || !filep || !conn->ctx) return; + + conn->must_close = 1; + conn->status_code = 207; + mg_printf(conn, "HTTP/1.1 207 Multi-Status\r\n" "Date: %s\r\n", date); + XX_httplib_send_static_cache_header(conn); + mg_printf(conn, "Connection: %s\r\n" "Content-Type: text/xml; charset=utf-8\r\n\r\n", XX_httplib_suggest_connection_header(conn)); + + conn->num_bytes_sent += mg_printf(conn, "" "\n"); + + /* Print properties for the requested resource itself */ + print_props(conn, conn->request_info.local_uri, filep); + + /* If it is a directory, print directory entries too if Depth is not 0 */ + if (filep && filep->is_directory + && !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes") + && (depth == NULL || strcmp(depth, "0") != 0)) { + XX_httplib_scan_directory(conn, path, conn, &print_dav_dir_entry); + } + + conn->num_bytes_sent += mg_printf(conn, "%s\n", ""); + +} /* XX_httplib_handle_propfind */ + +#endif diff --git a/src/libhttp-private.h b/src/libhttp-private.h index d6ce8324..3542fbc7 100644 --- a/src/libhttp-private.h +++ b/src/libhttp-private.h @@ -825,6 +825,14 @@ struct vec { enum { REQUEST_HANDLER, WEBSOCKET_HANDLER, AUTH_HANDLER }; +/* Directory entry */ +struct de { + struct mg_connection *conn; + char *file_name; + struct file file; +}; + + /* * Functions local to the server. These functions all begin with XX_httplib to @@ -907,9 +915,11 @@ int XX_httplib_refresh_trust( struct mg_connection *conn ); void XX_httplib_remove_bad_file( const struct mg_connection *conn, const char *path ); void XX_httplib_remove_double_dots_and_double_slashes( char *s ); void XX_httplib_reset_per_request_attributes( struct mg_connection *conn ); +int XX_httplib_scan_directory( struct mg_connection *conn, const char *dir, void *data, void (*cb)(struct de *, void *) ); void XX_httplib_send_authorization_request( struct mg_connection *conn ); void XX_httplib_send_http_error( struct mg_connection *, int, PRINTF_FORMAT_STRING(const char *fmt), ... ) PRINTF_ARGS(3, 4); void XX_httplib_send_options( struct mg_connection *conn ); +int XX_httplib_send_static_cache_header( struct mg_connection *conn ); int XX_httplib_send_websocket_handshake( struct mg_connection *conn, const char *websock_key ); int XX_httplib_set_acl_option( struct mg_context *ctx ); void XX_httplib_set_close_on_exec( SOCKET sock, struct mg_connection *conn ); diff --git a/src/libhttp.c b/src/libhttp.c index beeff483..fc0a06be 100644 --- a/src/libhttp.c +++ b/src/libhttp.c @@ -613,13 +613,6 @@ int XX_httplib_sTlsInit = 0; int XX_httplib_thread_idx_max = 0; -/* Directory entry */ -struct de { - struct mg_connection *conn; - char *file_name; - struct file file; -}; - @@ -1500,7 +1493,7 @@ static int send_no_cache_header(struct mg_connection *conn) { } -static int send_static_cache_header(struct mg_connection *conn) { +int XX_httplib_send_static_cache_header(struct mg_connection *conn) { #if !defined(NO_CACHING) /* Read the server config to check how long a file may be cached. @@ -1526,7 +1519,8 @@ static int send_static_cache_header(struct mg_connection *conn) { #else /* NO_CACHING */ return send_no_cache_header(conn); #endif /* !NO_CACHING */ -} + +} /* XX_httplib_send_static_cache_header */ void XX_httplib_send_http_error( struct mg_connection *conn, int status, const char *fmt, ... ) { @@ -4565,7 +4559,7 @@ int XX_httplib_must_hide_file( struct mg_connection *conn, const char *path ) { -static int scan_directory(struct mg_connection *conn, const char *dir, void *data, void (*cb)(struct de *, void *)) { +int XX_httplib_scan_directory( struct mg_connection *conn, const char *dir, void *data, void (*cb)(struct de *, void *) ) { char path[PATH_MAX]; struct dirent *dp; @@ -4605,7 +4599,8 @@ static int scan_directory(struct mg_connection *conn, const char *dir, void *dat (void)mg_closedir(dirp); } return 1; -} + +} /* XX_httplib_scan_directory */ #if !defined(NO_FILES) @@ -4714,7 +4709,7 @@ void XX_httplib_handle_directory_request( struct mg_connection *conn, const char char date[64]; time_t curtime = time(NULL); - if (!scan_directory(conn, dir, &data, dir_scan_callback)) { + if (!XX_httplib_scan_directory(conn, dir, &data, dir_scan_callback)) { XX_httplib_send_http_error(conn, 500, "Error: Cannot open directory\nopendir(%s): %s", dir, strerror(ERRNO)); return; } @@ -4727,7 +4722,7 @@ void XX_httplib_handle_directory_request( struct mg_connection *conn, const char conn->must_close = 1; mg_printf(conn, "HTTP/1.1 200 OK\r\n"); - send_static_cache_header(conn); + XX_httplib_send_static_cache_header(conn); mg_printf(conn, "Date: %s\r\n" "Connection: close\r\n" "Content-Type: text/html; charset=utf-8\r\n\r\n", date); conn->num_bytes_sent += @@ -4998,9 +4993,9 @@ void XX_httplib_handle_static_file_request( struct mg_connection *conn, const ch XX_httplib_gmt_time_string(lm, sizeof(lm), &filep->last_modified); construct_etag(etag, sizeof(etag), filep); - (void)mg_printf(conn, "HTTP/1.1 %d %s\r\n" "%s%s%s" "Date: %s\r\n", conn->status_code, msg, cors1, cors2, cors3, date); - send_static_cache_header(conn); - (void)mg_printf(conn, + mg_printf(conn, "HTTP/1.1 %d %s\r\n" "%s%s%s" "Date: %s\r\n", conn->status_code, msg, cors1, cors2, cors3, date); + XX_httplib_send_static_cache_header(conn); + mg_printf(conn, "Last-Modified: %s\r\n" "Etag: %s\r\n" "Content-Type: %.*s\r\n" @@ -5048,7 +5043,7 @@ void XX_httplib_handle_not_modified_static_file_request( struct mg_connection *c construct_etag(etag, sizeof(etag), filep); mg_printf(conn, "HTTP/1.1 %d %s\r\n" "Date: %s\r\n", conn->status_code, mg_get_response_code_text(conn, conn->status_code), date); - send_static_cache_header(conn); + XX_httplib_send_static_cache_header(conn); mg_printf(conn, "Last-Modified: %s\r\n" "Etag: %s\r\n" "Connection: %s\r\n" "\r\n", lm, etag, XX_httplib_suggest_connection_header(conn)); } /* XX_httplib_handle_not_modified_static_file_request */ @@ -5996,7 +5991,7 @@ void XX_httplib_mkcol( struct mg_connection *conn, const char *path ) { conn->status_code = 201; XX_httplib_gmt_time_string(date, sizeof(date), &curtime); mg_printf(conn, "HTTP/1.1 %d Created\r\n" "Date: %s\r\n", conn->status_code, date); - send_static_cache_header(conn); + XX_httplib_send_static_cache_header(conn); mg_printf(conn, "Content-Length: 0\r\n" "Connection: %s\r\n\r\n", XX_httplib_suggest_connection_header(conn)); } @@ -6404,82 +6399,4 @@ void XX_httplib_send_options( struct mg_connection *conn ) { } /* XX_httplib_send_options */ - -/* Writes PROPFIND properties for a collection element */ -static void print_props( struct mg_connection *conn, const char *uri, struct file *filep ) { - - char mtime[64]; - - if ( conn == NULL || uri == NULL || filep == NULL ) return; - - XX_httplib_gmt_time_string(mtime, sizeof(mtime), &filep->last_modified); - conn->num_bytes_sent += - mg_printf(conn, - "" - "%s" - "" - "" - "%s" - "%" INT64_FMT "" - "%s" - "" - "HTTP/1.1 200 OK" - "" - "\n", - uri, - filep->is_directory ? "" : "", - filep->size, - mtime); -} - - -static void print_dav_dir_entry(struct de *de, void *data) { - - char href[PATH_MAX]; - char href_encoded[PATH_MAX * 3 /* worst case */]; - int truncated; - - struct mg_connection *conn = (struct mg_connection *)data; - if (!de || !conn) return; - - XX_httplib_snprintf(conn, &truncated, href, sizeof(href), "%s%s", conn->request_info.local_uri, de->file_name); - - if (!truncated) { - mg_url_encode(href, href_encoded, PATH_MAX * 3); - print_props(conn, href_encoded, &de->file); - } -} - - -void XX_httplib_handle_propfind( struct mg_connection *conn, const char *path, struct file *filep ) { - - const char *depth = mg_get_header(conn, "Depth"); - char date[64]; - time_t curtime = time(NULL); - - XX_httplib_gmt_time_string(date, sizeof(date), &curtime); - - if (!conn || !path || !filep || !conn->ctx) return; - - conn->must_close = 1; - conn->status_code = 207; - mg_printf(conn, "HTTP/1.1 207 Multi-Status\r\n" "Date: %s\r\n", date); - send_static_cache_header(conn); - mg_printf(conn, "Connection: %s\r\n" "Content-Type: text/xml; charset=utf-8\r\n\r\n", XX_httplib_suggest_connection_header(conn)); - - conn->num_bytes_sent += mg_printf(conn, "" "\n"); - - /* Print properties for the requested resource itself */ - print_props(conn, conn->request_info.local_uri, filep); - - /* If it is a directory, print directory entries too if Depth is not 0 */ - if (filep && filep->is_directory - && !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes") - && (depth == NULL || strcmp(depth, "0") != 0)) { - scan_directory(conn, path, conn, &print_dav_dir_entry); - } - - conn->num_bytes_sent += mg_printf(conn, "%s\n", ""); - -} /* XX_httplib_handle_propfind */ #endif