diff options
Diffstat (limited to 'src/ostree/ostree-trivial-httpd.c')
-rw-r--r-- | src/ostree/ostree-trivial-httpd.c | 228 |
1 files changed, 167 insertions, 61 deletions
diff --git a/src/ostree/ostree-trivial-httpd.c b/src/ostree/ostree-trivial-httpd.c index 6b16737d..855d2cea 100644 --- a/src/ostree/ostree-trivial-httpd.c +++ b/src/ostree/ostree-trivial-httpd.c @@ -34,6 +34,19 @@ #include <sys/prctl.h> #include <signal.h> +#if ! SOUP_CHECK_VERSION (3, 0, 0) +# define SoupServerMessage SoupMessage +# define soup_server_message_get_method(msg) ((msg)->method) +# define soup_server_message_get_request_headers(msg) ((msg)->request_headers) +# define soup_server_message_get_response_headers(msg) ((msg)->response_headers) +# define soup_server_message_get_response_body(msg) ((msg)->response_body) +# define soup_server_message_set_status(msg, status) soup_message_set_status(msg, status) +# define soup_server_message_set_redirect(msg, status, uri) soup_message_set_redirect(msg, status, uri) +# define soup_server_message_set_response(msg, ct, ru, rb, rl) soup_message_set_response(msg, ct, ru, rb, rl) +#else +# define soup_server_message_set_status(msg, status) soup_server_message_set_status(msg, status, NULL) +#endif + static char *opt_port_file = NULL; static char *opt_log = NULL; static gboolean opt_daemonize; @@ -188,15 +201,12 @@ is_safe_to_access (struct stat *stbuf) } static void -close_socket (SoupMessage *msg, gpointer user_data) +close_socket (SoupServerMessage *msg, gpointer user_data) { - SoupSocket *sock = user_data; + GSocket *sock = user_data; int sockfd; - /* Actually calling soup_socket_disconnect() here would cause - * us to leak memory, so just shutdown the socket instead. - */ - sockfd = soup_socket_get_fd (sock); + sockfd = g_socket_get_fd (sock); #ifdef G_OS_WIN32 shutdown (sockfd, SD_SEND); #else @@ -213,12 +223,55 @@ calculate_etag (GMappedFile *mapping) return g_strconcat ("\"", checksum, "\"", NULL); } +static GSList * +_server_cookies_from_request (SoupServerMessage *msg) +{ + SoupCookie *cookie; + GSList *cookies = NULL; + GHashTable *params; + GHashTableIter iter; + gpointer name, value; + const char *header; + const char *host; + + header = soup_message_headers_get_one (soup_server_message_get_request_headers (msg), + "Cookie"); + if (!header) + return NULL; + +#if ! SOUP_CHECK_VERSION (3, 0, 0) + host = soup_uri_get_host (soup_message_get_uri (msg)); +#else + host = g_uri_get_host (soup_server_message_get_uri (msg)); +#endif + params = soup_header_parse_semi_param_list (header); + g_hash_table_iter_init (&iter, params); + + while (g_hash_table_iter_next (&iter, &name, &value)) + { + if (!name || !value) continue; + cookie = soup_cookie_new (name, value, host, NULL, 0); + cookies = g_slist_prepend (cookies, cookie); + } + + soup_header_free_param_list (params); + + return g_slist_reverse (cookies); +} + static void +#if ! SOUP_CHECK_VERSION (3, 0, 0) do_get (OtTrivialHttpd *self, SoupServer *server, - SoupMessage *msg, + SoupServerMessage *msg, const char *path, SoupClientContext *context) +#else +do_get (OtTrivialHttpd *self, + SoupServer *server, + SoupServerMessage *msg, + const char *path) +#endif { char *slash; int ret; @@ -228,7 +281,7 @@ do_get (OtTrivialHttpd *self, if (opt_expected_cookies) { - GSList *cookies = soup_cookies_from_request (msg); + GSList *cookies = _server_cookies_from_request (msg); GSList *l; int i; @@ -253,12 +306,12 @@ do_get (OtTrivialHttpd *self, if (!found) { httpd_log (self, "Expected cookie not found %s\n", k); - soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); - soup_cookies_free (cookies); + soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free); goto out; } } - soup_cookies_free (cookies); + g_slist_free_full (cookies, (GDestroyNotify)soup_cookie_free); } if (opt_expected_headers) @@ -273,18 +326,18 @@ do_get (OtTrivialHttpd *self, { g_autofree char *k = g_strndup (kv, eq - kv); const gchar *expected_v = eq + 1; - const gchar *found_v = soup_message_headers_get_one (msg->request_headers, k); + const gchar *found_v = soup_message_headers_get_one (soup_server_message_get_request_headers (msg), k); if (!found_v) { httpd_log (self, "Expected header not found %s\n", k); - soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN); goto out; } if (strcmp (found_v, expected_v) != 0) { httpd_log (self, "Expected header %s: %s but found %s\n", k, expected_v, found_v); - soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN); goto out; } } @@ -293,7 +346,7 @@ do_get (OtTrivialHttpd *self, if (strstr (path, "../") != NULL) { - soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN); goto out; } @@ -302,7 +355,7 @@ do_get (OtTrivialHttpd *self, g_random_int_range (0, 100) < opt_random_500s_percentage) { emitted_random_500s_count++; - soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); + soup_server_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); goto out; } else if (opt_random_408s_percentage > 0 && @@ -310,7 +363,7 @@ do_get (OtTrivialHttpd *self, g_random_int_range (0, 100) < opt_random_408s_percentage) { emitted_random_408s_count++; - soup_message_set_status (msg, SOUP_STATUS_REQUEST_TIMEOUT); + soup_server_message_set_status (msg, SOUP_STATUS_REQUEST_TIMEOUT); goto out; } @@ -323,17 +376,17 @@ do_get (OtTrivialHttpd *self, if (ret == -1) { if (errno == EPERM) - soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN); else if (errno == ENOENT) - soup_message_set_status (msg, SOUP_STATUS_NOT_FOUND); + soup_server_message_set_status (msg, SOUP_STATUS_NOT_FOUND); else - soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); + soup_server_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); goto out; } if (!is_safe_to_access (&stbuf)) { - soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN); goto out; } @@ -344,9 +397,13 @@ do_get (OtTrivialHttpd *self, { g_autofree char *redir_uri = NULL; - redir_uri = g_strdup_printf ("%s/", soup_message_get_uri (msg)->path); - soup_message_set_redirect (msg, SOUP_STATUS_MOVED_PERMANENTLY, - redir_uri); +#if ! SOUP_CHECK_VERSION (3, 0, 0) + redir_uri = g_strdup_printf ("%s/", soup_uri_get_path (soup_message_get_uri (msg))); +#else + redir_uri = g_strdup_printf ("%s/", g_uri_get_path (soup_server_message_get_uri (msg))); +#endif + soup_server_message_set_redirect (msg, SOUP_STATUS_MOVED_PERMANENTLY, + redir_uri); } else { @@ -354,15 +411,19 @@ do_get (OtTrivialHttpd *self, if (fstatat (self->root_dfd, index_realpath, &stbuf, 0) != -1) { g_autofree char *index_path = g_strconcat (path, "/index.html", NULL); +#if ! SOUP_CHECK_VERSION (3, 0, 0) do_get (self, server, msg, index_path, context); +#else + do_get (self, server, msg, index_path); +#endif } else { GString *listing = get_directory_listing (self->root_dfd, path); - soup_message_set_response (msg, "text/html", - SOUP_MEMORY_TAKE, - listing->str, listing->len); - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_response (msg, "text/html", + SOUP_MEMORY_TAKE, + listing->str, listing->len); + soup_server_message_set_status (msg, SOUP_STATUS_OK); g_string_free (listing, FALSE); } } @@ -371,21 +432,21 @@ do_get (OtTrivialHttpd *self, { if (!S_ISREG (stbuf.st_mode)) { - soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN); + soup_server_message_set_status (msg, SOUP_STATUS_FORBIDDEN); goto out; } glnx_autofd int fd = openat (self->root_dfd, path, O_RDONLY | O_CLOEXEC); if (fd < 0) { - soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); + soup_server_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); goto out; } g_autoptr(GMappedFile) mapping = g_mapped_file_new_from_fd (fd, FALSE, NULL); if (!mapping) { - soup_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); + soup_server_message_set_status (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR); goto out; } (void) close (fd); fd = -1; @@ -395,14 +456,14 @@ do_get (OtTrivialHttpd *self, if (last_modified != NULL) { g_autofree gchar *formatted = g_date_time_format (last_modified, "%a, %d %b %Y %H:%M:%S GMT"); - soup_message_headers_append (msg->response_headers, "Last-Modified", formatted); + soup_message_headers_append (soup_server_message_get_response_headers (msg), "Last-Modified", formatted); } g_autofree gchar *etag = calculate_etag (mapping); if (etag != NULL) - soup_message_headers_append (msg->response_headers, "ETag", etag); + soup_message_headers_append (soup_server_message_get_response_headers (msg), "ETag", etag); - if (msg->method == SOUP_METHOD_GET) + if (!strcmp (soup_server_message_get_method (msg), "GET")) { gsize buffer_length, file_size; SoupRange *ranges; @@ -410,13 +471,13 @@ do_get (OtTrivialHttpd *self, gboolean have_ranges; file_size = g_mapped_file_get_length (mapping); - have_ranges = soup_message_headers_get_ranges(msg->request_headers, file_size, &ranges, &ranges_length); + have_ranges = soup_message_headers_get_ranges(soup_server_message_get_request_headers (msg), file_size, &ranges, &ranges_length); if (opt_force_ranges && !have_ranges && g_strrstr (path, "/objects") != NULL) { - SoupSocket *sock; + GSocket *sock; buffer_length = file_size/2; - soup_message_headers_set_content_length (msg->response_headers, file_size); - soup_message_headers_append (msg->response_headers, + soup_message_headers_set_content_length (soup_server_message_get_response_headers (msg), file_size); + soup_message_headers_append (soup_server_message_get_response_headers (msg), "Connection", "close"); /* soup-message-io will wait for us to add @@ -424,7 +485,11 @@ do_get (OtTrivialHttpd *self, * the declared Content-Length. Instead, we * forcibly close the socket at that point. */ - sock = soup_client_context_get_socket (context); +#if ! SOUP_CHECK_VERSION (3, 0, 0) + sock = soup_client_context_get_gsocket (context); +#else + sock = soup_server_message_get_socket (msg); +#endif g_signal_connect (msg, "wrote-chunk", G_CALLBACK (close_socket), sock); } else @@ -434,12 +499,13 @@ do_get (OtTrivialHttpd *self, { if (ranges_length > 0 && ranges[0].start >= file_size) { - soup_message_set_status (msg, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE); - soup_message_headers_free_ranges (msg->request_headers, ranges); + soup_server_message_set_status (msg, SOUP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE); + soup_message_headers_free_ranges (soup_server_message_get_request_headers (msg), ranges); goto out; } - soup_message_headers_free_ranges (msg->request_headers, ranges); + soup_message_headers_free_ranges (soup_server_message_get_request_headers (msg), ranges); } +#if ! SOUP_CHECK_VERSION (3, 0, 0) if (buffer_length > 0) { SoupBuffer *buffer; @@ -451,8 +517,22 @@ do_get (OtTrivialHttpd *self, soup_message_body_append_buffer (msg->response_body, buffer); soup_buffer_free (buffer); } +#else + if (buffer_length > 0 && buffer_length == file_size) + { + GBytes *bytes = g_mapped_file_get_bytes (mapping); + soup_message_body_append_bytes (soup_server_message_get_response_body (msg), bytes); + g_bytes_unref (bytes); + } + else if (buffer_length > 0) + { + gchar *contents = g_mapped_file_get_contents (mapping); + soup_message_body_append (soup_server_message_get_response_body (msg), + SOUP_MEMORY_COPY, contents, buffer_length); + } +#endif } - else /* msg->method == SOUP_METHOD_HEAD */ + else /* method == HEAD */ { g_autofree char *length = NULL; @@ -461,56 +541,59 @@ do_get (OtTrivialHttpd *self, * But we'll optimize and avoid the extra I/O. */ length = g_strdup_printf ("%lu", (gulong)stbuf.st_size); - soup_message_headers_append (msg->response_headers, + soup_message_headers_append (soup_server_message_get_response_headers (msg), "Content-Length", length); } /* Check client’s caching headers. */ - const gchar *if_modified_since = soup_message_headers_get_one (msg->request_headers, + const gchar *if_modified_since = soup_message_headers_get_one (soup_server_message_get_request_headers (msg), "If-Modified-Since"); - const gchar *if_none_match = soup_message_headers_get_one (msg->request_headers, + const gchar *if_none_match = soup_message_headers_get_one (soup_server_message_get_request_headers (msg), "If-None-Match"); if (if_none_match != NULL && etag != NULL) { if (g_strcmp0 (etag, if_none_match) == 0) { - soup_message_set_status (msg, SOUP_STATUS_NOT_MODIFIED); - soup_message_body_truncate (msg->response_body); + soup_server_message_set_status (msg, SOUP_STATUS_NOT_MODIFIED); + soup_message_body_truncate (soup_server_message_get_response_body (msg)); } else { - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK); } } else if (if_modified_since != NULL && last_modified != NULL) { - SoupDate *if_modified_since_sd = soup_date_new_from_string (if_modified_since); g_autoptr(GDateTime) if_modified_since_dt = NULL; +#if ! SOUP_CHECK_VERSION (3, 0, 0) + SoupDate *if_modified_since_sd = soup_date_new_from_string (if_modified_since); if (if_modified_since_sd != NULL) if_modified_since_dt = g_date_time_new_from_unix_utc (soup_date_to_time_t (if_modified_since_sd)); +#else + if_modified_since_dt = soup_date_time_new_from_http_string (if_modified_since); +#endif if (if_modified_since_dt != NULL && g_date_time_compare (last_modified, if_modified_since_dt) <= 0) { - soup_message_set_status (msg, SOUP_STATUS_NOT_MODIFIED); - soup_message_body_truncate (msg->response_body); + soup_server_message_set_status (msg, SOUP_STATUS_NOT_MODIFIED); + soup_message_body_truncate (soup_server_message_get_response_body (msg)); } else { - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK); } - - g_clear_pointer (&if_modified_since_sd, soup_date_free); } else { - soup_message_set_status (msg, SOUP_STATUS_OK); + soup_server_message_set_status (msg, SOUP_STATUS_OK); } } out: { +#if ! SOUP_CHECK_VERSION (3, 0, 0) guint status = 0; g_autofree gchar *reason = NULL; @@ -518,26 +601,41 @@ do_get (OtTrivialHttpd *self, "status-code", &status, "reason-phrase", &reason, NULL); +#else + guint status = soup_server_message_get_status (msg); + const char *reason = soup_server_message_get_reason_phrase (msg); +#endif + httpd_log (self, " status: %s (%u)\n", reason, status); } return; } static void -httpd_callback (SoupServer *server, SoupMessage *msg, +#if ! SOUP_CHECK_VERSION (3, 0, 0) +httpd_callback (SoupServer *server, SoupServerMessage *msg, const char *path, GHashTable *query, SoupClientContext *context, gpointer data) +#else +httpd_callback (SoupServer *server, SoupServerMessage *msg, + const char *path, GHashTable *query, gpointer data) +#endif { OtTrivialHttpd *self = data; + const char *meth = soup_server_message_get_method (msg); - if (msg->method == SOUP_METHOD_GET || msg->method == SOUP_METHOD_HEAD) + if (!strcmp (meth, "GET") || !strcmp(meth, "HEAD")) +#if ! SOUP_CHECK_VERSION (3, 0, 0) do_get (self, server, msg, path, context); +#else + do_get (self, server, msg, path); +#endif else - soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); + soup_server_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); } static gboolean -basic_auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg, +basic_auth_callback (SoupAuthDomain *auth_domain, SoupServerMessage *msg, const char *username, const char *password, gpointer data) { return g_str_equal (username, "foouser") && g_str_equal (password, "barpw"); @@ -703,7 +801,7 @@ run (int argc, char **argv, GCancellable *cancellable, GError **error) } #if SOUP_CHECK_VERSION(2, 48, 0) - server = soup_server_new (SOUP_SERVER_SERVER_HEADER, "ostree-httpd ", NULL); + server = soup_server_new ("server-header", "ostree-httpd ", NULL); if (!soup_server_listen_all (server, opt_port, 0, error)) goto out; #else @@ -711,13 +809,21 @@ run (int argc, char **argv, GCancellable *cancellable, GError **error) SOUP_SERVER_SERVER_HEADER, "ostree-httpd ", NULL); #endif + if (opt_require_basic_auth) { +#if ! SOUP_CHECK_VERSION (3, 0, 0) glnx_unref_object SoupAuthDomain *auth_domain = soup_auth_domain_basic_new (SOUP_AUTH_DOMAIN_REALM, "auth-test", SOUP_AUTH_DOMAIN_ADD_PATH, "/", SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, basic_auth_callback, NULL); +#else + glnx_unref_object SoupAuthDomain *auth_domain = + soup_auth_domain_basic_new ("realm", "auth-test", NULL); + soup_auth_domain_add_path (auth_domain, "/"); + soup_auth_domain_basic_set_auth_callback (auth_domain, basic_auth_callback, NULL, NULL); +#endif soup_server_add_auth_domain (server, auth_domain); } |