From e217ed0b798706fd11d19f1ffc0bdbbb95d55f53 Mon Sep 17 00:00:00 2001 From: Maximilian Wuttke Date: Wed, 10 Mar 2021 17:26:38 +0100 Subject: [PATCH] Update to the newest version of XEP 0363 (HTTP Upload) Main changes: 1. Attributes instead of tags 2. Read the optional
tags and send them in the HTTP PUT header: * Authorization * Cookie * Expires Co-authored-by: Martin Dosch --- src/tools/http_upload.c | 27 +++++++++++++++++++++++++++ src/tools/http_upload.h | 5 +++++ src/xmpp/iq.c | 31 ++++++++++++++++++++++--------- src/xmpp/stanza.c | 27 +++------------------------ src/xmpp/stanza.h | 9 ++++++++- 5 files changed, 65 insertions(+), 34 deletions(-) diff --git a/src/tools/http_upload.c b/src/tools/http_upload.c index fcdd582a..ff72e1b9 100644 --- a/src/tools/http_upload.c +++ b/src/tools/http_upload.c @@ -166,6 +166,10 @@ http_file_put(void* userdata) char* err = NULL; char* content_type_header; + // Optional headers + char* auth_header = NULL; + char* cookie_header = NULL; + char* expires_header = NULL; CURL* curl; CURLcode res; @@ -196,6 +200,21 @@ http_file_put(void* userdata) } headers = curl_slist_append(headers, content_type_header); headers = curl_slist_append(headers, "Expect:"); + + // Optional headers + if (upload->authorization) { + asprintf(&auth_header, "Authorization: %s", upload->authorization); + headers = curl_slist_append(headers, auth_header); + } + if (upload->cookie) { + asprintf(&cookie_header, "Cookie: %s", upload->cookie); + headers = curl_slist_append(headers, cookie_header); + } + if (upload->expires) { + asprintf(&expires_header, "Expires: %s", upload->expires); + headers = curl_slist_append(headers, expires_header); + } + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); #if LIBCURL_VERSION_NUM >= 0x072000 @@ -225,6 +244,7 @@ http_file_put(void* userdata) curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)(upload->filesize)); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); + if ((res = curl_easy_perform(curl)) != CURLE_OK) { err = strdup(curl_easy_strerror(res)); } else { @@ -252,11 +272,15 @@ http_file_put(void* userdata) curl_easy_cleanup(curl); curl_global_cleanup(); curl_slist_free_all(headers); + if (fh) { fclose(fh); } free(content_type_header); free(output.buffer); + free(auth_header); + free(cookie_header); + free(expires_header); pthread_mutex_lock(&lock); g_free(cert_path); @@ -334,6 +358,9 @@ http_file_put(void* userdata) free(upload->put_url); free(upload->alt_scheme); free(upload->alt_fragment); + free(upload->authorization); + free(upload->cookie); + free(upload->expires); free(upload); return NULL; diff --git a/src/tools/http_upload.h b/src/tools/http_upload.h index 4e95d4d8..06145a43 100644 --- a/src/tools/http_upload.h +++ b/src/tools/http_upload.h @@ -59,6 +59,11 @@ typedef struct http_upload_t ProfWin* window; pthread_t worker; int cancel; + // Additional headers + // (NULL if they shouldn't be send in the PUT) + char* authorization; + char* cookie; + char* expires; } HTTPUpload; void* http_file_put(void* userdata); diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 5012d1a5..17e19297 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -2423,18 +2423,31 @@ _http_upload_response_id_handler(xmpp_stanza_t* const stanza, void* const userda xmpp_stanza_t* get = xmpp_stanza_get_child_by_name(slot, STANZA_NAME_GET); if (put && get) { - char* put_url = xmpp_stanza_get_text(put); - char* get_url = xmpp_stanza_get_text(get); - + const char* put_url = xmpp_stanza_get_attribute(put, "url"); upload->put_url = strdup(put_url); + const char* get_url = xmpp_stanza_get_attribute(get, "url"); upload->get_url = strdup(get_url); - xmpp_conn_t* conn = connection_get_conn(); - xmpp_ctx_t* ctx = xmpp_conn_get_context(conn); - if (put_url) - xmpp_free(ctx, put_url); - if (get_url) - xmpp_free(ctx, get_url); + // Optional "authorization", "cookie", "expires" headers + upload->authorization = upload->cookie = upload->expires = NULL; + xmpp_stanza_t* header = xmpp_stanza_get_children(put); + for (; header; header = xmpp_stanza_get_next(header)) { + if (g_strcmp0(xmpp_stanza_get_name(header), STANZA_NAME_HEADER) == 0) { + const char* header_name = xmpp_stanza_get_attribute(header, STANZA_ATTR_NAME); + if (g_strcmp0(header_name, STANZA_HEADER_AUTHORIZATION) == 0) { + upload->authorization = xmpp_stanza_get_text(header); + } + else if (g_strcmp0(header_name, STANZA_HEADER_COOKIE) == 0) { + upload->cookie = xmpp_stanza_get_text(header); + } + else if (g_strcmp0(header_name, STANZA_HEADER_EXPIRES) == 0) { + upload->expires = xmpp_stanza_get_text(header); + } + else { + log_warning("[HTTP upload] unknown header: %s", header_name); + } + } + } pthread_create(&(upload->worker), NULL, &http_file_put, upload); http_upload_add_upload(upload); diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 2b39a023..45c8f2c4 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -232,9 +232,6 @@ stanza_create_http_upload_request(xmpp_ctx_t* ctx, const char* const id, xmpp_stanza_set_name(request, STANZA_NAME_REQUEST); xmpp_stanza_set_ns(request, STANZA_NS_HTTP_UPLOAD); - xmpp_stanza_t* filename = xmpp_stanza_new(ctx); - xmpp_stanza_set_name(filename, STANZA_NAME_FILENAME); - xmpp_stanza_t* filename_txt = xmpp_stanza_new(ctx); char* filename_cpy = strdup(upload->filename); // strip spaces from filename (servers don't spaces) for (int i = 0; i < strlen(filename_cpy); i++) { @@ -242,34 +239,16 @@ stanza_create_http_upload_request(xmpp_ctx_t* ctx, const char* const id, filename_cpy[i] = '_'; } } - xmpp_stanza_set_text(filename_txt, basename(filename_cpy)); + xmpp_stanza_set_attribute(request, STANZA_ATTR_FILENAME, basename(filename_cpy)); free(filename_cpy); - xmpp_stanza_add_child(filename, filename_txt); - xmpp_stanza_add_child(request, filename); - xmpp_stanza_release(filename_txt); - xmpp_stanza_release(filename); - xmpp_stanza_t* size = xmpp_stanza_new(ctx); - xmpp_stanza_set_name(size, STANZA_NAME_SIZE); - xmpp_stanza_t* size_txt = xmpp_stanza_new(ctx); char* filesize = NULL; if (asprintf(&filesize, "%jd", (intmax_t)(upload->filesize)) != -1) { - xmpp_stanza_set_text(size_txt, filesize); + xmpp_stanza_set_attribute(request, STANZA_ATTR_SIZE, filesize); free(filesize); } - xmpp_stanza_add_child(size, size_txt); - xmpp_stanza_add_child(request, size); - xmpp_stanza_release(size_txt); - xmpp_stanza_release(size); - xmpp_stanza_t* content_type = xmpp_stanza_new(ctx); - xmpp_stanza_set_name(content_type, STANZA_NAME_CONTENT_TYPE); - xmpp_stanza_t* content_type_txt = xmpp_stanza_new(ctx); - xmpp_stanza_set_text(content_type_txt, upload->mime_type); - xmpp_stanza_add_child(content_type, content_type_txt); - xmpp_stanza_add_child(request, content_type); - xmpp_stanza_release(content_type_txt); - xmpp_stanza_release(content_type); + xmpp_stanza_set_attribute(request, STANZA_ATTR_CONTENTTYPE, upload->mime_type); xmpp_stanza_add_child(iq, request); xmpp_stanza_release(request); diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index a4ac6b33..a26bd6ff 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -106,6 +106,10 @@ #define STANZA_NAME_SLOT "slot" #define STANZA_NAME_PUT "put" #define STANZA_NAME_GET "get" +#define STANZA_NAME_HEADER "header" +#define STANZA_HEADER_AUTHORIZATION "Authorization" +#define STANZA_HEADER_COOKIE "Cookie" +#define STANZA_HEADER_EXPIRES "Expires" #define STANZA_NAME_URL "url" #define STANZA_NAME_COMMAND "command" #define STANZA_NAME_CONFIGURE "configure" @@ -178,6 +182,9 @@ #define STANZA_ATTR_STATUS "status" #define STANZA_ATTR_DATE "date" #define STANZA_ATTR_V4_FINGERPRINT "v4-fingerprint" +#define STANZA_ATTR_FILENAME "filename" +#define STANZA_ATTR_SIZE "size" +#define STANZA_ATTR_CONTENTTYPE "content-type" #define STANZA_TEXT_AWAY "away" #define STANZA_TEXT_DND "dnd" @@ -210,7 +217,7 @@ // XEP-0373: OpenPGP for XMPP #define STANZA_NS_OPENPGP_0 "urn:xmpp:openpgp:0" #define STANZA_NS_OPENPGP_0_PUBLIC_KEYS "urn:xmpp:openpgp:0:public-keys" -#define STANZA_NS_HTTP_UPLOAD "urn:xmpp:http:upload" +#define STANZA_NS_HTTP_UPLOAD "urn:xmpp:http:upload:0" #define STANZA_NS_X_OOB "jabber:x:oob" #define STANZA_NS_BLOCKING "urn:xmpp:blocking" #define STANZA_NS_COMMAND "http://jabber.org/protocol/commands"