From 9b86eb3d4a20cf6640d2ec1e733391c461772e8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Mon, 11 Jul 2016 16:17:02 +0200 Subject: [PATCH 01/33] Fix memset in init_url --- httpfs2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpfs2.c b/httpfs2.c index cb78eca..0f042af 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -667,7 +667,7 @@ static char * url_encode(char * path) { static int init_url(struct_url* url) { - memset(url, 0, sizeof(url)); + memset(url, 0, sizeof(*url)); url->sock_type = SOCK_CLOSED; url->timeout = TIMEOUT; #ifdef USE_SSL From 3b905bdd4563f97743f2f367a6153e1e39aacac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Mon, 11 Jul 2016 17:09:21 +0200 Subject: [PATCH 02/33] Add some fine informative messages. --- Makefile | 5 ++++- httpfs2.c | 25 +++++++++++++++++++------ 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 9497219..d3db29c 100644 --- a/Makefile +++ b/Makefile @@ -2,17 +2,20 @@ MAIN_CFLAGS := -g -Os -Wall $(shell pkg-config fuse --cflags) MAIN_CPPFLAGS := -Wall -Wno-unused-function -Wconversion -Wtype-limits -DUSE_AUTH -D_XOPEN_SOURCE=700 -D_ISOC99_SOURCE THR_CPPFLAGS := -DUSE_THREAD THR_LDFLAGS := -lpthread +GNUTLS_VERSION := 2.10 MAIN_LDFLAGS := $(shell pkg-config fuse --libs | sed -e s/-lrt// -e s/-ldl// -e s/-pthread// -e "s/ / /g") variants := -mt intermediates = -ifeq ($(shell pkg-config --atleast-version 2.10 gnutls ; echo $$?), 0) +ifeq ($(shell pkg-config --atleast-version $(GNUTLS_VERSION) gnutls ; echo $$?), 0) variants += -ssl -ssl-mt CERT_STORE := /etc/ssl/certs/ca-certificates.crt SSL_CPPFLAGS := -DUSE_SSL $(shell pkg-config gnutls --cflags) -DCERT_STORE=\"$(CERT_STORE)\" SSL_LDFLAGS := $(shell pkg-config gnutls --libs) +else + $(info GNUTLS version at least $(GNUTLS_VERSION) required for SSL support.) endif binbase = httpfs2 diff --git a/httpfs2.c b/httpfs2.c index 0f042af..1c22a87 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -69,6 +69,7 @@ static char* argv0; #define SOCK_CLOSED 0 #define SOCK_OPEN 1 #define SOCK_KEEPALIVE 2 +#define TNAM_LEN 9 typedef struct url { int proto; @@ -99,6 +100,7 @@ typedef struct url { size_t req_buf_size; off_t file_size; time_t last_modified; + char tname[TNAM_LEN]; } struct_url; static struct_url main_url; @@ -197,6 +199,7 @@ static int httpfs_stat(fuse_ino_t ino, struct stat *stbuf) case 2: { struct_url * url = thread_setup(); + fprintf(stderr, "Thread %s stat()\n", url->tname); /*DEBUG*/ stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; return (int) get_stat(url, stbuf); @@ -853,6 +856,7 @@ int main(int argc, char *argv[]) putenv("TZ=");/*UTC*/ argv0 = argv[0]; init_url(&main_url); + strncpy(main_url.tname, "main", TNAM_LEN - 1); while( argv[1] && (*(argv[1]) == '-') ) { @@ -1000,12 +1004,16 @@ int main(int argc, char *argv[]) */ static int close_client_socket(struct_url *url) { - if (url->sock_type == SOCK_KEEPALIVE) return SOCK_KEEPALIVE; + if (url->sock_type == SOCK_KEEPALIVE) { + fprintf(stderr, "Thread %s keeping socket open.\n", url->tname); /*DEBUG*/ + return SOCK_KEEPALIVE; + } return close_client_force(url); } static int close_client_force(struct_url *url) { if(url->sock_type != SOCK_CLOSED){ + fprintf(stderr, "Thread %s closing socket.\n", url->tname); /*DEBUG*/ #ifdef USE_SSL if (url->proto == PROTO_HTTPS) { gnutls_deinit(url->ss); @@ -1021,16 +1029,18 @@ static int close_client_force(struct_url *url) { static void destroy_url_copy(void * urlptr) { if(urlptr){ - fprintf(stderr, "%s: Thread %08lX ended.\n", argv0, pthread_self()); + fprintf(stderr, "%s: Thread %08lX ended.\n", argv0, pthread_self()); /*DEBUG*/ close_client_force(urlptr); free(urlptr); } } -static void * create_url_copy(const struct_url * url) +static struct_url * create_url_copy(const struct_url * url) { - void * res = malloc(sizeof(struct_url)); + struct_url * res = malloc(sizeof(struct_url)); memcpy(res, url, sizeof(struct_url)); + memset(res->tname, 0, TNAM_LEN); + snprintf(res->tname, TNAM_LEN - 1, "%08lX", pthread_self()); return res; } @@ -1038,7 +1048,7 @@ static struct_url * thread_setup(void) { struct_url * res = pthread_getspecific(url_key); if(!res) { - fprintf(stderr, "%s: Thread %08lX started.\n", argv0, pthread_self()); + fprintf(stderr, "%s: Thread %08lX started.\n", argv0, pthread_self()); /*DEBUG*/ res = create_url_copy(&main_url); pthread_setspecific(url_key, res); } @@ -1132,7 +1142,10 @@ static int open_client_socket(struct_url *url) { socklen_t sa_len; int sock_family, sock_type, sock_protocol; - if(url->sock_type == SOCK_KEEPALIVE) return url->sock_type; + if(url->sock_type == SOCK_KEEPALIVE) { + fprintf(stderr, "Thread %s reusing keepalive socket.\n", url->tname); /*DEBUG*/ + return url->sock_type; + } if(url->sock_type != SOCK_CLOSED) close_client_socket(url); (void) memset((void*) &sa, 0, sizeof(sa)); From d7523152b0851b9133279ce0c869ee4d9ac41239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Mon, 11 Jul 2016 17:13:55 +0200 Subject: [PATCH 03/33] Fix httpfs-ssl crash with http URL. --- httpfs2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/httpfs2.c b/httpfs2.c index 1c22a87..0fd88d5 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -451,6 +451,10 @@ print_ssl_info (gnutls_session_t session) gnutls_kx_algorithm_t kx; int dhe, ecdh; dhe = ecdh = 0; + if (!session) { + printf("No SSL session data.\n"); + return 0; + } /* print the key exchange’s algorithm name */ kx = gnutls_kx_get (session); From a9d073e157cb6f84829ace46cbaf52f723b16f13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Wed, 13 Jul 2016 09:35:01 +0200 Subject: [PATCH 04/33] make ssl prints use stderr to match rest of prints. --- httpfs2.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index 0fd88d5..a36cdbf 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -452,14 +452,14 @@ print_ssl_info (gnutls_session_t session) int dhe, ecdh; dhe = ecdh = 0; if (!session) { - printf("No SSL session data.\n"); + fprintf(stderr, "No SSL session data.\n"); return 0; } /* print the key exchange’s algorithm name */ kx = gnutls_kx_get (session); tmp = gnutls_kx_get_name (kx); - printf ("- Key Exchange: %s\n", tmp); + fprintf(stderr, "- Key Exchange: %s\n", tmp); /* Check the authentication type used and switch * to the appropriate. */ @@ -479,44 +479,44 @@ print_ssl_info (gnutls_session_t session) /* cert should have been printed when it was verified */ break; default: - printf("Not a x509 sesssion !?!\n"); + fprintf(stderr, "Not a x509 sesssion !?!\n"); } #if (GNUTLS_VERSION_MAJOR > 3 ) /* switch */ if (ecdh != 0) - printf ("- Ephemeral ECDH using curve %s\n", + fprintf(stderr, "- Ephemeral ECDH using curve %s\n", gnutls_ecc_curve_get_name (gnutls_ecc_curve_get (session))); else #endif if (dhe != 0) - printf ("- Ephemeral DH using prime of %d bits\n", + fprintf(stderr, "- Ephemeral DH using prime of %d bits\n", gnutls_dh_get_prime_bits (session)); /* print the protocol’s name (ie TLS 1.0) */ tmp = gnutls_protocol_get_name (gnutls_protocol_get_version (session)); - printf ("- Protocol: %s\n", tmp); + fprintf(stderr, "- Protocol: %s\n", tmp); /* print the certificate type of the peer. * ie X.509 */ tmp = gnutls_certificate_type_get_name (gnutls_certificate_type_get (session)); - printf ("- Certificate Type: %s\n", tmp); + fprintf(stderr, "- Certificate Type: %s\n", tmp); /* print the compression algorithm (if any) */ tmp = gnutls_compression_get_name (gnutls_compression_get (session)); - printf ("- Compression: %s\n", tmp); + fprintf(stderr, "- Compression: %s\n", tmp); /* print the name of the cipher used. * ie 3DES. */ tmp = gnutls_cipher_get_name (gnutls_cipher_get (session)); - printf ("- Cipher: %s\n", tmp); + fprintf(stderr, "- Cipher: %s\n", tmp); /* Print the MAC algorithms name. * ie SHA1 */ tmp = gnutls_mac_get_name (gnutls_mac_get (session)); - printf ("- MAC: %s\n", tmp); - printf ("Note: SSL paramaters may change as new connections are established to the server.\n"); + fprintf(stderr, "- MAC: %s\n", tmp); + fprintf(stderr, "Note: SSL paramaters may change as new connections are established to the server.\n"); return 0; } @@ -549,17 +549,17 @@ verify_certificate_callback (gnutls_session_t session) return GNUTLS_E_CERTIFICATE_ERROR; } if (status & GNUTLS_CERT_INVALID) - printf ("The server certificate is NOT trusted.\n"); + fprintf(stderr, "The server certificate is NOT trusted.\n"); if (status & GNUTLS_CERT_INSECURE_ALGORITHM) - printf ("The server certificate uses an insecure algorithm.\n"); + fprintf(stderr, "The server certificate uses an insecure algorithm.\n"); if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) - printf ("The server certificate hasn’t got a known issuer.\n"); + fprintf(stderr, "The server certificate hasn’t got a known issuer.\n"); if (status & GNUTLS_CERT_REVOKED) - printf ("The server certificate has been revoked.\n"); + fprintf(stderr, "The server certificate has been revoked.\n"); if (status & GNUTLS_CERT_EXPIRED) - printf ("The server certificate has expired\n"); + fprintf(stderr, "The server certificate has expired\n"); if (status & GNUTLS_CERT_NOT_ACTIVATED) - printf ("The server certificate is not yet activated\n"); + fprintf(stderr, "The server certificate is not yet activated\n"); /* Up to here the process is the same for X.509 certificates and * OpenPGP keys. From now on X.509 certificates are assumed. This can * be easily extended to work with openpgp keys as well. @@ -574,7 +574,7 @@ verify_certificate_callback (gnutls_session_t session) cert_list = gnutls_certificate_get_peers (session, &cert_list_size); if (cert_list == NULL) { - printf ("No server certificate was found!\n"); + fprintf(stderr, "No server certificate was found!\n"); return GNUTLS_E_CERTIFICATE_ERROR; } /* Check the hostname matches the certificate. @@ -586,7 +586,7 @@ verify_certificate_callback (gnutls_session_t session) return GNUTLS_E_CERTIFICATE_ERROR; } if (!(url->ssl_connected)) if (!gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_FULL, &data)) { - printf("%s", data.data); + fprintf(stderr, "%s", data.data); gnutls_free(data.data); } if (!hostname || !gnutls_x509_crt_check_hostname (cert, hostname)) @@ -596,7 +596,7 @@ verify_certificate_callback (gnutls_session_t session) int i; size_t len = strlen(hostname); if (*(hostname+len-1) == '.') len--; - if (!(url->ssl_connected)) printf ("Server hostname verification failed. Trying to peek into the cert.\n"); + if (!(url->ssl_connected)) fprintf(stderr, "Server hostname verification failed. Trying to peek into the cert.\n"); for (i=0;;i++) { char * dn = NULL; size_t dn_size = 0; @@ -612,7 +612,7 @@ verify_certificate_callback (gnutls_session_t session) if (len == dn_size) match = ! strncmp(dn, hostname, len); if (match) found = 1; - if (!(url->ssl_connected)) printf("Cert CN(%i): %s: %c\n", i, dn, match?'*':'X'); + if (!(url->ssl_connected)) fprintf(stderr, "Cert CN(%i): %s: %c\n", i, dn, match?'*':'X'); }} else ssl_error(dn_ret, session, "getting cert subject data"); @@ -622,7 +622,7 @@ verify_certificate_callback (gnutls_session_t session) } } if(!found){ - printf ("The server certificate’s owner does not match hostname ’%s’\n", + fprintf(stderr, "The server certificate’s owner does not match hostname ’%s’\n", hostname); return GNUTLS_E_CERTIFICATE_ERROR; } From e9b5166598f70cbdb12ca1ce11a2dc98c8d7ca83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Wed, 13 Jul 2016 10:52:08 +0200 Subject: [PATCH 05/33] make indentation uniform. --- httpfs2.c | 77 +++++++++++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index a36cdbf..740d291 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -203,11 +203,12 @@ static int httpfs_stat(fuse_ino_t ino, struct stat *stbuf) stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; return (int) get_stat(url, stbuf); - }; break; + } + break; default: - errno = ENOENT; - return -1; + errno = ENOENT; + return -1; } return 0; } @@ -382,18 +383,18 @@ static char * strndup(const char * str, size_t n){ static int mempref(const char * mem, const char * pref, size_t size, int case_sensitive) { /* return true if found */ - if (size < strlen(pref)) return 0; - if (case_sensitive) - return ! memcmp(mem, pref, strlen(pref)); - else { - int i; - for (i = 0; i < strlen(pref); i++) - /* Unless somebody calling setlocale() behind our back locale should be C. */ - /* It is important to not uppercase in languages like Turkish. */ - if (tolower(mem[i]) != tolower(pref[i])) - return 0; - return 1; - } + if (size < strlen(pref)) return 0; + if (case_sensitive) + return ! memcmp(mem, pref, strlen(pref)); + else { + int i; + for (i = 0; i < strlen(pref); i++) + /* Unless somebody calling setlocale() behind our back locale should be C. */ + /* It is important to not uppercase in languages like Turkish. */ + if (tolower(mem[i]) != tolower(pref[i])) + return 0; + return 1; + } } #ifdef USE_SSL @@ -443,7 +444,7 @@ unload_file (gnutls_datum_t data) * * Stolen from the GNUTLS docs. */ - int +int print_ssl_info (gnutls_session_t session) { const char *tmp; @@ -577,8 +578,7 @@ verify_certificate_callback (gnutls_session_t session) fprintf(stderr, "No server certificate was found!\n"); return GNUTLS_E_CERTIFICATE_ERROR; } - /* Check the hostname matches the certificate. - */ + /* Check the hostname matches the certificate. */ ret = gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER); if (ret < 0) { @@ -811,25 +811,25 @@ static int parse_url(const char * url, struct_url* res) static void usage(void) { - fprintf(stderr, "%s >>> Version: %s <<<\n", __FILE__, VERSION); - fprintf(stderr, "usage: %s [-c [console]] " + fprintf(stderr, "%s >>> Version: %s <<<\n", __FILE__, VERSION); + fprintf(stderr, "usage: %s [-c [console]] " #ifdef USE_SSL - "[-a file] [-d n] [-5] [-2] " + "[-a file] [-d n] [-5] [-2] " #endif - "[-f] [-t timeout] [-r] url mount-parameters\n\n", argv0); - fprintf(stderr, "\t -c \tuse console for standard input/output/error (default: %s)\n", CONSOLE); + "[-f] [-t timeout] [-r] url mount-parameters\n\n", argv0); + fprintf(stderr, "\t -c \tuse console for standard input/output/error (default: %s)\n", CONSOLE); #ifdef USE_SSL - fprintf(stderr, "\t -a \tCA file used to verify server certificate\n"); - fprintf(stderr, "\t -d \tGNUTLS debug level\n"); - fprintf(stderr, "\t -5 \tAllow RSA-MD5 cert\n"); - fprintf(stderr, "\t -2 \tAllow RSA-MD2 cert\n"); + fprintf(stderr, "\t -a \tCA file used to verify server certificate\n"); + fprintf(stderr, "\t -d \tGNUTLS debug level\n"); + fprintf(stderr, "\t -5 \tAllow RSA-MD5 cert\n"); + fprintf(stderr, "\t -2 \tAllow RSA-MD2 cert\n"); #endif - fprintf(stderr, "\t -f \tstay in foreground - do not fork\n"); + fprintf(stderr, "\t -f \tstay in foreground - do not fork\n"); #ifdef RETRY_ON_RESET - fprintf(stderr, "\t -r \tretry connection on reset\n"); + fprintf(stderr, "\t -r \tretry connection on reset\n"); #endif - fprintf(stderr, "\t -t \tset socket timeout in seconds (default: %i)\n", TIMEOUT); - fprintf(stderr, "\tmount-parameters should include the mount point\n"); + fprintf(stderr, "\t -t \tset socket timeout in seconds (default: %i)\n", TIMEOUT); + fprintf(stderr, "\tmount-parameters should include the mount point\n"); } #define shift { if(!argv[1]) { usage(); return 4; };\ @@ -1074,7 +1074,7 @@ static ssize_t read_client_socket(struct_url *url, void * buf, size_t len) { if (url->proto == PROTO_HTTPS) { res = gnutls_record_recv(url->ss, buf, len); if (res <= 0) ssl_error((int)res, url->ss, "read"); - } else + } else #endif { res = read(url->sockfd, buf, len); @@ -1095,10 +1095,10 @@ write_client_socket(struct_url *url, const void * buf, size_t len) if (url->proto == PROTO_HTTPS) { res = gnutls_record_send(url->ss, buf, len); if (res <= 0) ssl_error((int)res, url->ss, "write"); - /* - * It is suggested to retry GNUTLS_E_INTERRUPTED and GNUTLS_E_AGAIN - * However, retrying only causes delay in practice. FIXME - */ + /* + * It is suggested to retry GNUTLS_E_INTERRUPTED and GNUTLS_E_AGAIN + * However, retrying only causes delay in practice. FIXME + */ } else #endif { @@ -1149,7 +1149,7 @@ static int open_client_socket(struct_url *url) { if(url->sock_type == SOCK_KEEPALIVE) { fprintf(stderr, "Thread %s reusing keepalive socket.\n", url->tname); /*DEBUG*/ return url->sock_type; - } + } if(url->sock_type != SOCK_CLOSED) close_client_socket(url); (void) memset((void*) &sa, 0, sizeof(sa)); @@ -1436,7 +1436,7 @@ exchange(struct_url *url, char * buf, const char * method, bytes += (size_t)snprintf(buf + bytes, HEADER_SIZE - bytes, "User-Agent: %s %s\r\n", __FILE__, VERSION); if (range) bytes += (size_t)snprintf(buf + bytes, HEADER_SIZE - bytes, - "Range: bytes=%" PRIdMAX "-%" PRIdMAX "\r\n", (intmax_t)start, (intmax_t)end); + "Range: bytes=%" PRIdMAX "-%" PRIdMAX "\r\n", (intmax_t)start, (intmax_t)end); #ifdef USE_AUTH if ( url->auth ) bytes += (size_t)snprintf(buf + bytes, HEADER_SIZE - bytes, @@ -1444,7 +1444,6 @@ exchange(struct_url *url, char * buf, const char * method, #endif bytes += (size_t)snprintf(buf + bytes, HEADER_SIZE - bytes, "\r\n"); - /* Now actually send it. */ while(1){ /* From 654b998e533dc82dba4bffe77c4abb8c182af9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Wed, 13 Jul 2016 16:34:09 +0200 Subject: [PATCH 06/33] Update GnuTLS code to work better with GnuTLS 3. --- httpfs2.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/httpfs2.c b/httpfs2.c index 740d291..bdfdcb9 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -1020,6 +1020,7 @@ static int close_client_force(struct_url *url) { fprintf(stderr, "Thread %s closing socket.\n", url->tname); /*DEBUG*/ #ifdef USE_SSL if (url->proto == PROTO_HTTPS) { + gnutls_bye(url->ss, GNUTLS_SHUT_RDWR); gnutls_deinit(url->ss); } #endif @@ -1257,6 +1258,8 @@ static int open_client_socket(struct_url *url) { r = gnutls_init(&url->ss, GNUTLS_CLIENT); if (!r) gnutls_session_set_ptr(url->ss, url); /* used in cert verifier */ if (!r) r = gnutls_priority_set_direct(url->ss, ps, &errp); + if (!r) errp = NULL; + /* alternative to gnutls_priority_set_direct: if (!r) gnutls_set_default_priority(url->ss); */ if (!r) r = gnutls_credentials_set(url->ss, GNUTLS_CRD_CERTIFICATE, url->sc); if (!r) gnutls_transport_set_ptr(url->ss, (gnutls_transport_ptr_t) (intptr_t) url->sockfd); if (!r) r = gnutls_handshake (url->ss); /* FIXME gnutls_error_is_fatal is recommended here */ From 902193c29e7d731def1ca08fa0c1ddba3156634b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Wed, 13 Jul 2016 17:08:37 +0200 Subject: [PATCH 07/33] Fix recommends of fusermount fuse-utils -> fuse in Jessie --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 813b73b..603afa1 100644 --- a/debian/control +++ b/debian/control @@ -13,7 +13,7 @@ Homepage: http://sourceforge.net/projects/httpfs/ Package: httpfs2 Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, -Recommends: fuse-utils +Recommends: fuse-utils | fuse (>= 2.9.3~) Description: FUSE filesystem for mounting files from http servers httpfs2 is a FUSE based filesystem for mounting http or https URLS as files in the filesystem. There is no notion of listable directories in http so only a From a2317d66e99671514894b1d164ef9f5bf210c006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Wed, 13 Jul 2016 17:11:45 +0200 Subject: [PATCH 08/33] fix man page typo --- httpfs2.1.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpfs2.1.txt b/httpfs2.1.txt index 9cf166d..c273719 100644 --- a/httpfs2.1.txt +++ b/httpfs2.1.txt @@ -23,7 +23,7 @@ single URL can be mounted. The server must be able to send byte ranges. OPTIONS ------- *-c 'console'*:: - Attempt to use the file ior device 'console' for output after fork. + Attempt to use the file or device 'console' for output after fork. The default is '/dev/console'. *-f*:: From b6cd288b471da3740cb23291cb69879ca78ce067 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Wed, 13 Jul 2016 17:20:13 +0200 Subject: [PATCH 09/33] Reorder options in help text alphabetically. --- httpfs2.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index bdfdcb9..86e1163 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -817,12 +817,14 @@ static void usage(void) "[-a file] [-d n] [-5] [-2] " #endif "[-f] [-t timeout] [-r] url mount-parameters\n\n", argv0); - fprintf(stderr, "\t -c \tuse console for standard input/output/error (default: %s)\n", CONSOLE); #ifdef USE_SSL + fprintf(stderr, "\t -2 \tAllow RSA-MD2 server certificate\n"); + fprintf(stderr, "\t -5 \tAllow RSA-MD5 server certificate\n"); fprintf(stderr, "\t -a \tCA file used to verify server certificate\n"); +#endif + fprintf(stderr, "\t -c \tuse console for standard input/output/error (default: %s)\n", CONSOLE); +#ifdef USE_SSL fprintf(stderr, "\t -d \tGNUTLS debug level\n"); - fprintf(stderr, "\t -5 \tAllow RSA-MD5 cert\n"); - fprintf(stderr, "\t -2 \tAllow RSA-MD2 cert\n"); #endif fprintf(stderr, "\t -f \tstay in foreground - do not fork\n"); #ifdef RETRY_ON_RESET From e595bd8f44bf0064cf1c5425540515d13f5aff5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Wed, 13 Jul 2016 17:31:48 +0200 Subject: [PATCH 10/33] Improve help text formatting. --- httpfs2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index 86e1163..a74d8fa 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -820,9 +820,9 @@ static void usage(void) #ifdef USE_SSL fprintf(stderr, "\t -2 \tAllow RSA-MD2 server certificate\n"); fprintf(stderr, "\t -5 \tAllow RSA-MD5 server certificate\n"); - fprintf(stderr, "\t -a \tCA file used to verify server certificate\n"); + fprintf(stderr, "\t -a \tCA file used to verify server certificate\n\t\t(default: %s)\n", CERT_STORE); #endif - fprintf(stderr, "\t -c \tuse console for standard input/output/error (default: %s)\n", CONSOLE); + fprintf(stderr, "\t -c \tuse console for standard input/output/error\n\t\t(default: %s)\n", CONSOLE); #ifdef USE_SSL fprintf(stderr, "\t -d \tGNUTLS debug level\n"); #endif From 70ade57d0c7d49c14ea3f2eafcfe1fdc1f60652d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Wed, 13 Jul 2016 17:39:58 +0200 Subject: [PATCH 11/33] Add SSL options to man page. --- httpfs2.1.txt | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/httpfs2.1.txt b/httpfs2.1.txt index c273719..f6bb225 100644 --- a/httpfs2.1.txt +++ b/httpfs2.1.txt @@ -32,16 +32,35 @@ OPTIONS *-t 'timeout'*:: Use different timeout for connections. Default '30's. -*'URL'*:: - The url should specify the protocol as http or https, and it may specify - basic authentication username and password. Currently special characters - like whitespace are not handled so the URL cannot contain them. See a - sample URL below: +SSL OPTIONS +~~~~~~~~~~~ +Available when SSL support is compiled in. + +*-2*:: + Allow server certificates signed with RSA-MD2 (strongly discouraged) + +*-5*:: + Allow server certificates signed with RSA-MD5 (discouraged) + +*-a 'CA file'*:: + Specify a file to load trusted CA root certificates from. + A default location is set at build time. + +*-d 'n'*:: + Set GnuTLS debug level to numeric value n. + +*'URL'* +~~~~~~~ +The url should specify the protocol as http or https, and it may specify basic +authentication username and password. Currently special characters like +whitespace are not handled so the URL cannot contain them. See a sample URL +below: http://user:password@server.com/dir/file -*'FUSE-OPTIONS'*:: - These options are passed to the *FUSE* library. At the very least the mount point should be specified. +*'FUSE-OPTIONS'* +~~~~~~~~~~~~~~~~ +These options are passed to the *FUSE* library. At the very least the mount point should be specified. EXIT STATUS From 2d511652c4aa9a69397f96bad9aeeaca7ad1df0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Thu, 14 Jul 2016 15:18:56 +0200 Subject: [PATCH 12/33] HTTP Redirect support. --- httpfs2.c | 173 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 145 insertions(+), 28 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index a74d8fa..d703e81 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -61,19 +61,27 @@ static pthread_key_t url_key; #define TIMEOUT 30 #define CONSOLE "/dev/console" #define HEADER_SIZE 1024 +#define MAX_REQUEST (32*1024) +#define MAX_REDIRECTS 32 +#define TNAM_LEN 9 #define VERSION "0.1.5 \"The Message\"" -static char* argv0; +enum sock_state { + SOCK_CLOSED, + SOCK_OPEN, + SOCK_KEEPALIVE, +}; -#define MAX_REQUEST (32*1024) -#define SOCK_CLOSED 0 -#define SOCK_OPEN 1 -#define SOCK_KEEPALIVE 2 -#define TNAM_LEN 9 +enum url_flags { + URL_DUP, + URL_SAVE, + URL_DROP, +}; typedef struct url { int proto; long timeout; + char * url; char * host; /*hostname*/ int port; char * path; /*get path*/ @@ -85,7 +93,9 @@ typedef struct url { int retry_reset; /*retry reset connections*/ #endif int sockfd; - int sock_type; + enum sock_state sock_type; + int redirected; + int redirect_depth; #ifdef USE_SSL long ssl_log_level; unsigned md5; @@ -104,6 +114,7 @@ typedef struct url { } struct_url; static struct_url main_url; +static char* argv0; static off_t get_stat(struct_url*, struct stat * stbuf); static ssize_t get_data(struct_url*, off_t start, size_t size); @@ -685,6 +696,8 @@ static int init_url(struct_url* url) static int free_url(struct_url* url) { + if(url->sock_type != SOCK_CLOSED) + close_client_force(url); if(url->host) free(url->host); url->host = 0; if(url->path) free(url->path); @@ -695,8 +708,6 @@ static int free_url(struct_url* url) if(url->auth) free(url->auth); url->auth = 0; #endif - if(url->sock_type != SOCK_CLOSED) - close_client_force(url); url->port = 0; url->proto = 0; /* only after socket closed */ url->file_size=0; @@ -727,15 +738,39 @@ static void print_url(FILE *f, const struct_url * url) #endif } -static int parse_url(const char * url, struct_url* res) +static int parse_url(char * _url, struct_url* res, enum url_flags flag) { - const char * url_orig = url; - char* http = "http://"; + const char * url_orig; + const char * url; + const char * http = "http://"; #ifdef USE_SSL - char* https = "https://"; + const char * https = "https://"; #endif /* USE_SSL */ int path_start = '/'; - assert(url); + + if (!_url) + _url = res->url; + assert(_url); + switch(flag) { + case URL_DUP: + _url = strdup(_url); + case URL_SAVE: + assert (_url != res->url); + if (res->url) + free(res->url); + res->url = _url; + break; + case URL_DROP: + assert (res->url); + break; + } + /* constify so compiler warns about modification */ + url_orig = url = _url; + + close_client_force(res); +#ifdef USE_SSL + res->ssl_connected = 0; +#endif if (strncmp(http, url, strlen(http)) == 0) { url += strlen(http); @@ -753,6 +788,8 @@ static int parse_url(const char * url, struct_url* res) } /* determine if path was given */ + if(res->path) + free(res->path); if(strchr(url, path_start)) res->path = url_encode(strchr(url, path_start)); else{ @@ -763,6 +800,8 @@ static int parse_url(const char * url, struct_url* res) #ifdef USE_AUTH /* Get user and password */ + if(res->auth) + free(res->auth); if(strchr(url, '@') && (strchr(url, '@') < strchr(url, path_start))){ res->auth = b64_encode((unsigned char *)url, strchr(url, '@') - url); url = strchr(url, '@') + 1; @@ -787,6 +826,8 @@ static int parse_url(const char * url, struct_url* res) fprintf(stderr, "No hostname in url: %s\n", url_orig); return -1; } + if(res->host) + free(res->host); res->host = strndup(url, (size_t)(strchr(url, host_end) - url)); /* Get the file name. */ @@ -797,6 +838,8 @@ static int parse_url(const char * url, struct_url* res) /* Handle broken urls with multiple slashes. */ while((end > url) && (*end == '/')) end--; end++; + if(res->name) + free(res->name); if((path_start == 0) || (end == url) || (strncmp(url, "/", (size_t)(end - url)) == 0)){ res->name = strdup(res->host); @@ -910,7 +953,7 @@ int main(int argc, char *argv[]) usage(); return 1; } - if(parse_url(argv[1], &main_url) == -1){ + if(parse_url(argv[1], &main_url, URL_DUP) == -1){ fprintf(stderr, "invalid url: %s\n", argv[1]); return 2; } @@ -1022,6 +1065,7 @@ static int close_client_force(struct_url *url) { fprintf(stderr, "Thread %s closing socket.\n", url->tname); /*DEBUG*/ #ifdef USE_SSL if (url->proto == PROTO_HTTPS) { + fprintf(stderr, "Thread %s closing SSL socket.\n", url->tname); gnutls_bye(url->ss, GNUTLS_SHUT_RDWR); gnutls_deinit(url->ss); } @@ -1037,7 +1081,7 @@ static void destroy_url_copy(void * urlptr) { if(urlptr){ fprintf(stderr, "%s: Thread %08lX ended.\n", argv0, pthread_self()); /*DEBUG*/ - close_client_force(urlptr); + free_url(urlptr); free(urlptr); } } @@ -1046,6 +1090,16 @@ static struct_url * create_url_copy(const struct_url * url) { struct_url * res = malloc(sizeof(struct_url)); memcpy(res, url, sizeof(struct_url)); + if(url->name) + res->name = strdup(url->name); + if(url->host) + res->host = strdup(url->host); + if(url->path) + res->path = strdup(url->path); +#ifdef USE_AUTH + if(url->auth) + res->auth = strdup(url->auth); +#endif memset(res->tname, 0, TNAM_LEN); snprintf(res->tname, TNAM_LEN - 1, "%08lX", pthread_self()); return res; @@ -1153,8 +1207,17 @@ static int open_client_socket(struct_url *url) { fprintf(stderr, "Thread %s reusing keepalive socket.\n", url->tname); /*DEBUG*/ return url->sock_type; } + if(url->sock_type != SOCK_CLOSED) close_client_socket(url); + if(url->redirected) { + fprintf(stderr, "Thread %s returning from redirect to master %s\n", url->tname, url->url); + url->redirect_depth = 0; + url->redirected = 0; + parse_url(NULL, url, URL_DROP); + print_url(stderr, url); + } + (void) memset((void*) &sa, 0, sizeof(sa)); #ifdef USE_IPV6 @@ -1257,6 +1320,7 @@ static int open_client_socket(struct_url *url) { return -1; } + fprintf(stderr, "Thread %s initializing SSL socket.\n", url->tname); r = gnutls_init(&url->ss, GNUTLS_CLIENT); if (!r) gnutls_session_set_ptr(url->ss, url); /* used in cert verifier */ if (!r) r = gnutls_priority_set_direct(url->ss, ps, &errp); @@ -1270,6 +1334,7 @@ static int open_client_socket(struct_url *url) { if (errp) fprintf(stderr, "%s: invalid SSL priority\n %s\n %*s\n", argv0, ps, (int)(errp - ps), "^"); fprintf(stderr, "%s: %s:%d - ", argv0, url->host, url->port); ssl_error(r, url->ss, "SSL connection failed"); + fprintf(stderr, "Thread %s closing SSL socket.\n", url->tname); gnutls_deinit(url->ss); errno = EIO; return -1; @@ -1341,6 +1406,54 @@ parse_header(struct_url *url, const char * buf, size_t bytes, return -1; } status = (int)strtol( ptr + strlen(http), (char **)&ptr, 10); + if (status == 301 || status == 302 || status == 307 || status == 303) { + char * location = "Location: "; + ptrdiff_t llen = (ptrdiff_t) strlen(location); + + while(1) { + ptr = end+1; + if( !(ptr < buf + (header_len - 4))){ + close_client_force(url); + plain_report("redirect did not contain a Location header!", + method, buf, 0); + return -1; + } + + end = memchr(ptr, '\n', bytes - (size_t)(ptr - buf)); + if (mempref(ptr, location, (size_t)(end - ptr), 0) ){ + size_t len = (size_t) (end - ptr - llen); + char * tmp = malloc(len + 1); + int res; + + tmp[len] = 0; + strncpy(tmp, ptr + llen, len); + + url->redirect_depth ++; + if (url->redirect_depth > MAX_REDIRECTS) { + fprintf(stderr, "Server redirected %i times already. Giving up.", MAX_REDIRECTS); + return -EIO; + } + + if (status == 301) { + fprintf(stderr, "Permanent redirect to %s\n", tmp); + + res = parse_url(tmp, url, URL_SAVE); + } else { + fprintf(stderr, "Temporary redirect to %s\n", tmp); + + url->redirected = 1; + res = parse_url(tmp, url, URL_DROP); + free(tmp); + } + + if(res < 0) + return res; + + print_url(stderr, url); + return -EAGAIN; + } + } + } if (status != expect) { fprintf(stderr, "%s: %s: failed with status: %d%.*s.\n", argv0, method, status, (int)((end - ptr) - 1), ptr); @@ -1434,6 +1547,7 @@ exchange(struct_url *url, char * buf, const char * method, size_t bytes; int range = (end > 0); +req: /* Build request buffer, starting with the request method. */ bytes = (size_t)snprintf(buf, HEADER_SIZE, "%s %s HTTP/1.1\r\nHost: %s\r\n", @@ -1490,21 +1604,24 @@ exchange(struct_url *url, char * buf, const char * method, } else if (res <= 0) { errno_report("exchange: failed receving reply from server"); /* DEBUG */ return res; - } else break; - /* Not reached */ - } - bytes = (size_t)res; + } else { + bytes = (size_t)res; - res = parse_header(url, buf, bytes, method, content_length, - range ? 206 : 200); - if (res <= 0){ - plain_report("exchange: server error", method, buf, bytes); - return res; - } + res = parse_header(url, buf, bytes, method, content_length, + range ? 206 : 200); + if (res == -EAGAIN) /* redirect */ + goto req; + + if (res <= 0){ + plain_report("exchange: server error", method, buf, bytes); + return res; + } - if (header_length) *header_length = (size_t)res; + if (header_length) *header_length = (size_t)res; - return (ssize_t)bytes; + return (ssize_t)bytes; + } + } } /* From 0072b35e252c58b255a89529189e33eae3bb1a2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Thu, 14 Jul 2016 18:03:16 +0200 Subject: [PATCH 13/33] Fix temporary redirect. --- httpfs2.c | 58 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index d703e81..f54ae31 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -95,6 +95,7 @@ typedef struct url { int sockfd; enum sock_state sock_type; int redirected; + int redirect_followed; int redirect_depth; #ifdef USE_SSL long ssl_log_level; @@ -830,24 +831,27 @@ static int parse_url(char * _url, struct_url* res, enum url_flags flag) free(res->host); res->host = strndup(url, (size_t)(strchr(url, host_end) - url)); - /* Get the file name. */ - url = strchr(url, path_start); - const char * end = url + strlen(url); - end--; - - /* Handle broken urls with multiple slashes. */ - while((end > url) && (*end == '/')) end--; - end++; - if(res->name) - free(res->name); - if((path_start == 0) || (end == url) - || (strncmp(url, "/", (size_t)(end - url)) == 0)){ - res->name = strdup(res->host); - }else{ - while(strchr(url, '/') && (strchr(url, '/') < end)) - url = strchr(url, '/') + 1; - res->name = strndup(url, (size_t)(end - url)); - } + if(flag != URL_DROP) { + /* Get the file name. */ + url = strchr(url, path_start); + const char * end = url + strlen(url); + end--; + + /* Handle broken urls with multiple slashes. */ + while((end > url) && (*end == '/')) end--; + end++; + if(res->name) + free(res->name); + if((path_start == 0) || (end == url) + || (strncmp(url, "/", (size_t)(end - url)) == 0)){ + res->name = strdup(res->host); + }else{ + while(strchr(url, '/') && (strchr(url, '/') < end)) + url = strchr(url, '/') + 1; + res->name = strndup(url, (size_t)(end - url)); + } + } else + assert(res->name); return res->proto; } @@ -1072,6 +1076,15 @@ static int close_client_force(struct_url *url) { #endif close(url->sockfd); } + + if(url->redirected && url->redirect_followed) { + fprintf(stderr, "%s: %s: returning from redirect to master %s\n", argv0, url->tname, url->url); + url->redirect_depth = 0; + url->redirect_followed = 0; + url->redirected = 0; + parse_url(NULL, url, URL_DROP); + print_url(stderr, url); + } return url->sock_type = SOCK_CLOSED; } @@ -1210,13 +1223,8 @@ static int open_client_socket(struct_url *url) { if(url->sock_type != SOCK_CLOSED) close_client_socket(url); - if(url->redirected) { - fprintf(stderr, "Thread %s returning from redirect to master %s\n", url->tname, url->url); - url->redirect_depth = 0; - url->redirected = 0; - parse_url(NULL, url, URL_DROP); - print_url(stderr, url); - } + if (url->redirected) + url->redirect_followed = 1; (void) memset((void*) &sa, 0, sizeof(sa)); From afacbdf86bb09bf24980ecb417c5745c86e26e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Thu, 14 Jul 2016 18:05:59 +0200 Subject: [PATCH 14/33] More uniform log messages. --- httpfs2.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index f54ae31..8a573b9 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -63,7 +63,7 @@ static pthread_key_t url_key; #define HEADER_SIZE 1024 #define MAX_REQUEST (32*1024) #define MAX_REDIRECTS 32 -#define TNAM_LEN 9 +#define TNAM_LEN 13 #define VERSION "0.1.5 \"The Message\"" enum sock_state { @@ -111,7 +111,7 @@ typedef struct url { size_t req_buf_size; off_t file_size; time_t last_modified; - char tname[TNAM_LEN]; + char tname[TNAM_LEN + 1]; } struct_url; static struct_url main_url; @@ -211,7 +211,7 @@ static int httpfs_stat(fuse_ino_t ino, struct stat *stbuf) case 2: { struct_url * url = thread_setup(); - fprintf(stderr, "Thread %s stat()\n", url->tname); /*DEBUG*/ + fprintf(stderr, "%s: %s: stat()\n", argv0, url->tname); /*DEBUG*/ stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; return (int) get_stat(url, stbuf); @@ -658,21 +658,23 @@ static void logfunc(int level, const char * str) static void ssl_error(int error, gnutls_session_t ss, const char * where) { + struct_url * url = thread_setup(); const char * err_desc; if((error == GNUTLS_E_FATAL_ALERT_RECEIVED) || (error == GNUTLS_E_WARNING_ALERT_RECEIVED)) err_desc = gnutls_alert_get_name(gnutls_alert_get(ss)); else err_desc = gnutls_strerror(error); - fprintf(stderr, "%s: %s: %d %s.\n", argv0, where, error, err_desc); + fprintf(stderr, "%s: %s: %s: %d %s.\n", argv0, url->tname, where, error, err_desc); errno = EIO; /* FIXME is this used anywhere? */ } #endif static void errno_report(const char * where) { + struct_url * url = thread_setup(); int e = errno; - fprintf(stderr, "%s: %s: %d %s.\n", argv0, where, errno, strerror(errno)); + fprintf(stderr, "%s: %s: %s: %d %s.\n", argv0, url->tname, where, errno, strerror(errno)); errno = e; } @@ -909,7 +911,7 @@ int main(int argc, char *argv[]) putenv("TZ=");/*UTC*/ argv0 = argv[0]; init_url(&main_url); - strncpy(main_url.tname, "main", TNAM_LEN - 1); + strncpy(main_url.tname, "main", TNAM_LEN); while( argv[1] && (*(argv[1]) == '-') ) { @@ -1058,7 +1060,7 @@ int main(int argc, char *argv[]) static int close_client_socket(struct_url *url) { if (url->sock_type == SOCK_KEEPALIVE) { - fprintf(stderr, "Thread %s keeping socket open.\n", url->tname); /*DEBUG*/ + fprintf(stderr, "%s: %s: keeping socket open.\n", argv0, url->tname); /*DEBUG*/ return SOCK_KEEPALIVE; } return close_client_force(url); @@ -1066,10 +1068,10 @@ static int close_client_socket(struct_url *url) { static int close_client_force(struct_url *url) { if(url->sock_type != SOCK_CLOSED){ - fprintf(stderr, "Thread %s closing socket.\n", url->tname); /*DEBUG*/ + fprintf(stderr, "%s: %s: closing socket.\n", argv0, url->tname); /*DEBUG*/ #ifdef USE_SSL if (url->proto == PROTO_HTTPS) { - fprintf(stderr, "Thread %s closing SSL socket.\n", url->tname); + fprintf(stderr, "%s: %s: closing SSL socket.\n", argv0, url->tname); gnutls_bye(url->ss, GNUTLS_SHUT_RDWR); gnutls_deinit(url->ss); } @@ -1113,8 +1115,8 @@ static struct_url * create_url_copy(const struct_url * url) if(url->auth) res->auth = strdup(url->auth); #endif - memset(res->tname, 0, TNAM_LEN); - snprintf(res->tname, TNAM_LEN - 1, "%08lX", pthread_self()); + memset(res->tname, 0, TNAM_LEN + 1); + snprintf(res->tname, TNAM_LEN, "%0*lX", TNAM_LEN, pthread_self()); return res; } @@ -1217,7 +1219,7 @@ static int open_client_socket(struct_url *url) { int sock_family, sock_type, sock_protocol; if(url->sock_type == SOCK_KEEPALIVE) { - fprintf(stderr, "Thread %s reusing keepalive socket.\n", url->tname); /*DEBUG*/ + fprintf(stderr, "%s: %s: reusing keepalive socket.\n", argv0, url->tname); /*DEBUG*/ return url->sock_type; } @@ -1328,7 +1330,7 @@ static int open_client_socket(struct_url *url) { return -1; } - fprintf(stderr, "Thread %s initializing SSL socket.\n", url->tname); + fprintf(stderr, "%s: %s: initializing SSL socket.\n", argv0, url->tname); r = gnutls_init(&url->ss, GNUTLS_CLIENT); if (!r) gnutls_session_set_ptr(url->ss, url); /* used in cert verifier */ if (!r) r = gnutls_priority_set_direct(url->ss, ps, &errp); @@ -1342,7 +1344,7 @@ static int open_client_socket(struct_url *url) { if (errp) fprintf(stderr, "%s: invalid SSL priority\n %s\n %*s\n", argv0, ps, (int)(errp - ps), "^"); fprintf(stderr, "%s: %s:%d - ", argv0, url->host, url->port); ssl_error(r, url->ss, "SSL connection failed"); - fprintf(stderr, "Thread %s closing SSL socket.\n", url->tname); + fprintf(stderr, "%s: %s: closing SSL socket.\n", argv0, url->tname); gnutls_deinit(url->ss); errno = EIO; return -1; @@ -1357,7 +1359,9 @@ static void plain_report(const char * reason, const char * method, const char * buf, size_t len) { - fprintf(stderr, "%s: %s: %s\n", argv0, method, reason); + struct_url * url = thread_setup(); + + fprintf(stderr, "%s: %s: %s: %s\n", argv0, url->tname, method, reason); fwrite(buf, len, 1, stderr); if(len && ( *(buf+len-1) != '\n')) fputc('\n', stderr); } @@ -1438,16 +1442,16 @@ parse_header(struct_url *url, const char * buf, size_t bytes, url->redirect_depth ++; if (url->redirect_depth > MAX_REDIRECTS) { - fprintf(stderr, "Server redirected %i times already. Giving up.", MAX_REDIRECTS); + fprintf(stderr, "%s: %s: server redirected %i times already. Giving up.", argv0, url->tname, MAX_REDIRECTS); return -EIO; } if (status == 301) { - fprintf(stderr, "Permanent redirect to %s\n", tmp); + fprintf(stderr, "%s: %s: permanent redirect to %s\n", argv0, url->tname, tmp); res = parse_url(tmp, url, URL_SAVE); } else { - fprintf(stderr, "Temporary redirect to %s\n", tmp); + fprintf(stderr, "%s: %s: temporary redirect to %s\n", argv0, url->tname, tmp); url->redirected = 1; res = parse_url(tmp, url, URL_DROP); From bbd157fc49d279ff403d27075bd3d4d1af2a6ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Thu, 14 Jul 2016 18:26:44 +0200 Subject: [PATCH 15/33] Saner name for a couple of symbols. --- httpfs2.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index 8a573b9..8b5e99c 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -63,7 +63,7 @@ static pthread_key_t url_key; #define HEADER_SIZE 1024 #define MAX_REQUEST (32*1024) #define MAX_REDIRECTS 32 -#define TNAM_LEN 13 +#define TNAME_LEN 13 #define VERSION "0.1.5 \"The Message\"" enum sock_state { @@ -111,7 +111,7 @@ typedef struct url { size_t req_buf_size; off_t file_size; time_t last_modified; - char tname[TNAM_LEN + 1]; + char tname[TNAME_LEN + 1]; } struct_url; static struct_url main_url; @@ -911,7 +911,7 @@ int main(int argc, char *argv[]) putenv("TZ=");/*UTC*/ argv0 = argv[0]; init_url(&main_url); - strncpy(main_url.tname, "main", TNAM_LEN); + strncpy(main_url.tname, "main", TNAME_LEN); while( argv[1] && (*(argv[1]) == '-') ) { @@ -1115,8 +1115,8 @@ static struct_url * create_url_copy(const struct_url * url) if(url->auth) res->auth = strdup(url->auth); #endif - memset(res->tname, 0, TNAM_LEN + 1); - snprintf(res->tname, TNAM_LEN, "%0*lX", TNAM_LEN, pthread_self()); + memset(res->tname, 0, TNAME_LEN + 1); + snprintf(res->tname, TNAME_LEN, "%0*lX", TNAME_LEN, pthread_self()); return res; } @@ -1356,7 +1356,7 @@ static int open_client_socket(struct_url *url) { } static void -plain_report(const char * reason, const char * method, +http_report(const char * reason, const char * method, const char * buf, size_t len) { struct_url * url = thread_setup(); @@ -1392,7 +1392,7 @@ parse_header(struct_url *url, const char * buf, size_t bytes, end = memchr(ptr, '\n', bytes); if(!end) { - plain_report ( "reply does not contain newline!", method, buf, 0); + http_report ( "reply does not contain newline!", method, buf, 0); errno = EIO; return -1; } @@ -1400,7 +1400,7 @@ parse_header(struct_url *url, const char * buf, size_t bytes, while(1){ end = memchr(end + 1, '\n', bytes - (size_t)(end - ptr)); if(!end || ((end + 1) >= (ptr + bytes)) ) { - plain_report ("reply does not contain end of header!", + http_report ("reply does not contain end of header!", method, buf, bytes); errno = EIO; return -1; @@ -1412,7 +1412,7 @@ parse_header(struct_url *url, const char * buf, size_t bytes, end = memchr(ptr, '\n', bytes); char * http = "HTTP/1.1 "; if(!mempref(ptr, http, (size_t)(end - ptr), 1) || !isdigit( *(ptr + strlen(http))) ) { - plain_report ("reply does not contain status!", + http_report ("reply does not contain status!", method, buf, (size_t)header_len); errno = EIO; return -1; @@ -1426,7 +1426,7 @@ parse_header(struct_url *url, const char * buf, size_t bytes, ptr = end+1; if( !(ptr < buf + (header_len - 4))){ close_client_force(url); - plain_report("redirect did not contain a Location header!", + http_report("redirect did not contain a Location header!", method, buf, 0); return -1; } @@ -1495,17 +1495,17 @@ parse_header(struct_url *url, const char * buf, size_t bytes, close_client_force(url); errno = EIO; if(! seen_accept){ - plain_report("server must Accept-Range: bytes", + http_report("server must Accept-Range: bytes", method, buf, 0); return -1; } if(! seen_length){ - plain_report("reply didn't contain Content-Length!", + http_report("reply didn't contain Content-Length!", method, buf, 0); return -1; } /* fallback - should not reach */ - plain_report("error parsing header.", + http_report("error parsing header.", method, buf, 0); return -1; @@ -1529,7 +1529,7 @@ parse_header(struct_url *url, const char * buf, size_t bytes, memset(&tm, 0, sizeof(tm)); if(!strptime(ptr + strlen(date), "%n%a, %d %b %Y %T %Z", &tm)){ - plain_report("invalid time", + http_report("invalid time", method, ptr + strlen(date), (size_t)(end - ptr) - strlen(date)) ; continue; @@ -1625,7 +1625,7 @@ exchange(struct_url *url, char * buf, const char * method, goto req; if (res <= 0){ - plain_report("exchange: server error", method, buf, bytes); + http_report("exchange: server error", method, buf, bytes); return res; } @@ -1674,7 +1674,7 @@ static ssize_t get_data(struct_url *url, off_t start, size_t size) if(bytes <= 0) return -1; if (content_length != size) { - plain_report("didn't yield the whole piece.", "GET", 0, 0); + http_report("didn't yield the whole piece.", "GET", 0, 0); size = min((size_t)content_length, size); } From 7c559f9b6f6effe8d26941c14c545ec06e1a4c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Fri, 15 Jul 2016 14:02:31 +0200 Subject: [PATCH 16/33] Improve handling of ECONNRESET this is untested --- httpfs2.1.txt | 5 +++++ httpfs2.c | 56 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/httpfs2.1.txt b/httpfs2.1.txt index f6bb225..19fdcf7 100644 --- a/httpfs2.1.txt +++ b/httpfs2.1.txt @@ -22,6 +22,7 @@ single URL can be mounted. The server must be able to send byte ranges. OPTIONS ------- + *-c 'console'*:: Attempt to use the file or device 'console' for output after fork. The default is '/dev/console'. @@ -29,6 +30,10 @@ OPTIONS *-f*:: Do not fork, stay in foreground. +*-r 'retries'*:: + (if 'ECONNRESET' is defined) Retry connecting to server after receiving + 'ECONNRESET'. Defaults to 8 times which gives about 30s timeout. + *-t 'timeout'*:: Use different timeout for connections. Default '30's. diff --git a/httpfs2.c b/httpfs2.c index 8b5e99c..dd91b5a 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -58,12 +58,21 @@ static pthread_key_t url_key; #include #endif +/* + * ECONNRESET happens with some dodgy servers so may need to handle that. + * Allow for building without ECONNRESET in case it is not defined. + */ +#ifdef ECONNRESET +#define RETRY_ON_RESET +#endif + #define TIMEOUT 30 #define CONSOLE "/dev/console" #define HEADER_SIZE 1024 #define MAX_REQUEST (32*1024) #define MAX_REDIRECTS 32 #define TNAME_LEN 13 +#define RESET_RETRIES 8 #define VERSION "0.1.5 \"The Message\"" enum sock_state { @@ -90,7 +99,8 @@ typedef struct url { char * auth; /*encoded auth data*/ #endif #ifdef RETRY_ON_RESET - int retry_reset; /*retry reset connections*/ + long retry_reset; /*retry reset connections*/ + long resets; #endif int sockfd; enum sock_state sock_type; @@ -691,6 +701,9 @@ static int init_url(struct_url* url) memset(url, 0, sizeof(*url)); url->sock_type = SOCK_CLOSED; url->timeout = TIMEOUT; +#ifdef RETRY_ON_RESET + url->retry_reset = RESET_RETRIES; +#endif #ifdef USE_SSL url->cafile = CERT_STORE; #endif @@ -865,7 +878,7 @@ static void usage(void) #ifdef USE_SSL "[-a file] [-d n] [-5] [-2] " #endif - "[-f] [-t timeout] [-r] url mount-parameters\n\n", argv0); + "[-f] [-t timeout] [-r n] url mount-parameters\n\n", argv0); #ifdef USE_SSL fprintf(stderr, "\t -2 \tAllow RSA-MD2 server certificate\n"); fprintf(stderr, "\t -5 \tAllow RSA-MD5 server certificate\n"); @@ -873,11 +886,11 @@ static void usage(void) #endif fprintf(stderr, "\t -c \tuse console for standard input/output/error\n\t\t(default: %s)\n", CONSOLE); #ifdef USE_SSL - fprintf(stderr, "\t -d \tGNUTLS debug level\n"); + fprintf(stderr, "\t -d \tGNUTLS debug level (default 0)\n"); #endif fprintf(stderr, "\t -f \tstay in foreground - do not fork\n"); #ifdef RETRY_ON_RESET - fprintf(stderr, "\t -r \tretry connection on reset\n"); + fprintf(stderr, "\t -r \tnumber of times to retry connection on reset\n\t\t(default: %i)\n", RESET_RETRIES); #endif fprintf(stderr, "\t -t \tset socket timeout in seconds (default: %i)\n", TIMEOUT); fprintf(stderr, "\tmount-parameters should include the mount point\n"); @@ -938,7 +951,9 @@ int main(int argc, char *argv[]) break; #endif #ifdef RETRY_ON_RESET - case 'r': main_url.retry_reset = 1; + case 'r': if (convert_num(&main_url.retry_reset, argv)) + return 4; + shift; break; #endif case 't': if (convert_num(&main_url.timeout, argv)) @@ -1588,17 +1603,21 @@ exchange(struct_url *url, char * buf, const char * method, * required to touch it but are handled as error below. * */ - /* ECONNRESET happens with some dodgy servers so may need to handle that. - * Allow for building without it in case it is not defined. - */ -#ifdef RETRY_ON_RESET -#define CONNFAIL ((res <= 0) && ! errno) || (errno == EAGAIN) || (errno == EPIPE) || \ - (url->retry_reset && (errno == ECONNRESET)) -#else #define CONNFAIL ((res <= 0) && ! errno) || (errno == EAGAIN) || (errno == EPIPE) -#endif + errno = 0; res = write_client_socket(url, buf, bytes); + +#ifdef RETRY_ON_RESET + if ((errno == ECONNRESET) && (url->resets < url->retry_reset)) { + errno_report("exchange: sleeping"); + sleep(1U << url->resets); + url->resets ++; + close_client_force(url); + continue; + } + url->resets = 0; +#endif if (CONNFAIL) { errno_report("exchange: failed to send request, retrying"); /* DEBUG */ close_client_force(url); @@ -1609,6 +1628,17 @@ exchange(struct_url *url, char * buf, const char * method, return res; } res = read_client_socket(url, buf, HEADER_SIZE); + +#ifdef RETRY_ON_RESET + if ((errno == ECONNRESET) && (url->resets < url->retry_reset)) { + errno_report("exchange: sleeping"); + sleep(1U << url->resets); + url->resets ++; + close_client_force(url); + continue; + } + url->resets = 0; +#endif if (CONNFAIL) { errno_report("exchange: did not receive a reply, retrying"); /* DEBUG */ close_client_force(url); From 9e8f181cfe5dedb6cb9d71b24fed3844b10df02c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Fri, 15 Jul 2016 14:43:15 +0200 Subject: [PATCH 17/33] Set errno on getaddrinfo error. --- httpfs2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/httpfs2.c b/httpfs2.c index dd91b5a..e12a443 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -1253,6 +1253,7 @@ static int open_client_socket(struct_url *url) { if ((gaierr = getaddrinfo(url->host, portstr, &hints, &ai)) != 0) { (void) fprintf(stderr, "%s: getaddrinfo %s - %s\n", argv0, url->host, gai_strerror(gaierr)); + errno = EIO; return -1; } From 8a5889c92c51964c368eb97d68361ce0b4e0344e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Fri, 15 Jul 2016 14:55:53 +0200 Subject: [PATCH 18/33] Unify error reporting in open_client_socket --- httpfs2.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index e12a443..70fdcf7 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -1243,6 +1243,8 @@ static int open_client_socket(struct_url *url) { if (url->redirected) url->redirect_followed = 1; + fprintf(stderr, "%s: %s: connecting to %s port %i.\n", argv0, url->tname, url->host, url->port); + (void) memset((void*) &sa, 0, sizeof(sa)); #ifdef USE_IPV6 @@ -1251,8 +1253,8 @@ static int open_client_socket(struct_url *url) { hints.ai_socktype = SOCK_STREAM; (void) snprintf(portstr, sizeof(portstr), "%d", (int) url->port); if ((gaierr = getaddrinfo(url->host, portstr, &hints, &ai)) != 0) { - (void) fprintf(stderr, "%s: getaddrinfo %s - %s\n", - argv0, url->host, gai_strerror(gaierr)); + (void) fprintf(stderr, "%s: %s: getaddrinfo %s - %s\n", + argv0, url->tname, url->host, gai_strerror(gaierr)); errno = EIO; return -1; } @@ -1269,14 +1271,14 @@ static int open_client_socket(struct_url *url) { if (aiv4 == NULL) aiv4 = aiv6; if (aiv4 == NULL) { - (void) fprintf(stderr, "%s: no valid address found for host %s\n", - argv0, url->host); + (void) fprintf(stderr, "%s: %s: no valid address found for host %s\n", + argv0, url->tname, url->host); errno = EIO; return -1; } if (sizeof(sa) < aiv4->ai_addrlen) { - (void) fprintf(stderr, "%s - sockaddr too small (%lu < %lu)\n", - url->host, (unsigned long) sizeof(sa), + (void) fprintf(stderr, "%s: %s: %s - sockaddr too small (%lu < %lu)\n", + argv0, url->tname, url->host, (unsigned long) sizeof(sa), (unsigned long) aiv4->ai_addrlen); errno = EIO; return -1; @@ -1292,7 +1294,7 @@ static int open_client_socket(struct_url *url) { he = gethostbyname(url->host); if (he == NULL) { - (void) fprintf(stderr, "%s: unknown host - %s\n", argv0, url->host); + (void) fprintf(stderr, "%s: %s: unknown host - %s\n", argv0, url->tname, url->host); errno = EIO; return -1; } @@ -1308,7 +1310,6 @@ static int open_client_socket(struct_url *url) { url->sockfd = socket(sock_family, sock_type, sock_protocol); if (url->sockfd < 0) { errno_report("couldn't get socket"); - return -1; } if (connect(url->sockfd, (struct sockaddr*) &sa, sa_len) < 0) { From 4676d9a26b7dd92d4cd967c160c76c7b49a0ceb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Fri, 15 Jul 2016 15:14:49 +0200 Subject: [PATCH 19/33] Rebuild request when returning from redirect. --- httpfs2.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index 70fdcf7..3fe2055 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -1093,6 +1093,7 @@ static int close_client_force(struct_url *url) { #endif close(url->sockfd); } + url->sock_type = SOCK_CLOSED; if(url->redirected && url->redirect_followed) { fprintf(stderr, "%s: %s: returning from redirect to master %s\n", argv0, url->tname, url->url); @@ -1101,8 +1102,9 @@ static int close_client_force(struct_url *url) { url->redirected = 0; parse_url(NULL, url, URL_DROP); print_url(stderr, url); + return -EAGAIN; } - return url->sock_type = SOCK_CLOSED; + return url->sock_type; } #ifdef USE_THREAD @@ -1615,18 +1617,22 @@ exchange(struct_url *url, char * buf, const char * method, errno_report("exchange: sleeping"); sleep(1U << url->resets); url->resets ++; - close_client_force(url); + if (close_client_force(url) == -EAGAIN) + goto req; continue; } url->resets = 0; #endif if (CONNFAIL) { errno_report("exchange: failed to send request, retrying"); /* DEBUG */ - close_client_force(url); + if (close_client_force(url) == -EAGAIN) + goto req; continue; } if (res <= 0){ errno_report("exchange: failed to send request"); /* DEBUG */ + if (close_client_force(url) == -EAGAIN) + goto req; return res; } res = read_client_socket(url, buf, HEADER_SIZE); @@ -1636,17 +1642,21 @@ exchange(struct_url *url, char * buf, const char * method, errno_report("exchange: sleeping"); sleep(1U << url->resets); url->resets ++; - close_client_force(url); + if (close_client_force(url) == -EAGAIN) + goto req; continue; } url->resets = 0; #endif if (CONNFAIL) { errno_report("exchange: did not receive a reply, retrying"); /* DEBUG */ - close_client_force(url); + if (close_client_force(url) == -EAGAIN) + goto req; continue; } else if (res <= 0) { errno_report("exchange: failed receving reply from server"); /* DEBUG */ + if (close_client_force(url) == -EAGAIN) + goto req; return res; } else { bytes = (size_t)res; From e6b546e401dddaf85c1072211a0df463988e7d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Fri, 15 Jul 2016 15:22:36 +0200 Subject: [PATCH 20/33] Reset redirect count only when a socket was closed. Otherwise httpfs could loop accessing an URL redirecting to non-reachable server. --- httpfs2.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/httpfs2.c b/httpfs2.c index 3fe2055..9774cd4 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -1082,6 +1082,8 @@ static int close_client_socket(struct_url *url) { } static int close_client_force(struct_url *url) { + int sock_closed = 0; + if(url->sock_type != SOCK_CLOSED){ fprintf(stderr, "%s: %s: closing socket.\n", argv0, url->tname); /*DEBUG*/ #ifdef USE_SSL @@ -1092,12 +1094,13 @@ static int close_client_force(struct_url *url) { } #endif close(url->sockfd); + sock_closed = 1; } url->sock_type = SOCK_CLOSED; if(url->redirected && url->redirect_followed) { fprintf(stderr, "%s: %s: returning from redirect to master %s\n", argv0, url->tname, url->url); - url->redirect_depth = 0; + if (sock_closed) url->redirect_depth = 0; url->redirect_followed = 0; url->redirected = 0; parse_url(NULL, url, URL_DROP); From 99a92eeda4d53c97d3af6a44991104a79cae7ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Fri, 15 Jul 2016 17:12:45 +0200 Subject: [PATCH 21/33] Fix crash in option parsing. This is reported in Debian bug #716022 When not enough arguments are provided by the user NULL argument is dereferenced in option parser. Require one more argument to be non-null since at least two non-option arguments are required anyway. This is a cosmetical change - instead of segfault usage message is printed. The referenced argument is guaranteed to be null and cause crash without the extra check. --- httpfs2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/httpfs2.c b/httpfs2.c index 9774cd4..c4417b9 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -896,7 +896,7 @@ static void usage(void) fprintf(stderr, "\tmount-parameters should include the mount point\n"); } -#define shift { if(!argv[1]) { usage(); return 4; };\ +#define shift { if(!argv[1] || !argv[2]) { usage(); return 4; };\ argc--; argv[1] = argv[0]; argv = argv + 1;} static int convert_num(long * num, char ** argv) From 2482808849b879cb90efdc168d38c45aa06aedf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Fri, 15 Jul 2016 17:26:36 +0200 Subject: [PATCH 22/33] Update Debian changelog --- debian/changelog | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/debian/changelog b/debian/changelog index 3a7b243..0576fb3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,13 @@ +httpfs2 (0.1.5-2) UNRELEASED; urgency=medium + + * New upstream release: + - (Closes: #705310) (LP: #1046266) + - miscellaneous bug fixes + (Closes: #698179, #716022, #729027) + - HTTP redirect support + + -- Michal Suchanek Fri, 15 Jul 2016 17:16:08 +0200 + httpfs2 (0.1.5-1) unstable; urgency=low * New upstream release: From 6f2945087baa2bd5546670871f4a28de0c4bfb9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Fri, 15 Jul 2016 17:26:48 +0200 Subject: [PATCH 23/33] Update copyright --- debian/copyright | 2 +- httpfs2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/copyright b/debian/copyright index 9e82a46..a68c543 100644 --- a/debian/copyright +++ b/debian/copyright @@ -5,7 +5,7 @@ Download: http://sourceforge.net/projects/httpfs/ Files: * Copyright: - (C) 2008-2012 Michal Suchanek + (C) 2008-2012,2016 Michal Suchanek (C) 2006 hmb (C) 2001-2007 Miklos Szeredi License: GPL-2+ diff --git a/httpfs2.c b/httpfs2.c index c4417b9..ad95cbd 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -19,7 +19,7 @@ * Modified to work with fuse 2.7. * Added keepalive * The passthru functionality removed to simplify the code. - * (c) 2008-2012 Michal Suchanek + * (c) 2008-2012,2016 Michal Suchanek * */ From 433f67704b437198976cfabd6edadc10018b8e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Tue, 19 Jul 2016 17:04:40 +0200 Subject: [PATCH 24/33] Install multithreaded version in Debian. --- debian/changelog | 1 + debian/compat | 2 +- debian/control | 2 +- debian/httpfs2-ssl.install | 3 ++- debian/httpfs2.install | 3 ++- 5 files changed, 7 insertions(+), 4 deletions(-) mode change 100644 => 100755 debian/httpfs2-ssl.install mode change 100644 => 100755 debian/httpfs2.install diff --git a/debian/changelog b/debian/changelog index 0576fb3..d4bd722 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,7 @@ httpfs2 (0.1.5-2) UNRELEASED; urgency=medium - miscellaneous bug fixes (Closes: #698179, #716022, #729027) - HTTP redirect support + * install multithreaded version -- Michal Suchanek Fri, 15 Jul 2016 17:16:08 +0200 diff --git a/debian/compat b/debian/compat index 7f8f011..ec63514 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -7 +9 diff --git a/debian/control b/debian/control index 603afa1..41bfd4e 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: web Priority: extra Maintainer: Michal Suchanek Build-Depends: - debhelper (>= 7.0.50~), + debhelper (>= 9~), dh-exec, asciidoc, xmlto, libfuse-dev (>> 2.6), pkg-config, libgnutls-dev (>= 2.10~), diff --git a/debian/httpfs2-ssl.install b/debian/httpfs2-ssl.install old mode 100644 new mode 100755 index 7cb4ad5..2c0717b --- a/debian/httpfs2-ssl.install +++ b/debian/httpfs2-ssl.install @@ -1 +1,2 @@ -httpfs2-ssl /usr/bin +#!/usr/bin/dh-exec +httpfs2-ssl-mt => /usr/bin/httpfs2-ssl diff --git a/debian/httpfs2.install b/debian/httpfs2.install old mode 100644 new mode 100755 index 0867b91..241d642 --- a/debian/httpfs2.install +++ b/debian/httpfs2.install @@ -1 +1,2 @@ -httpfs2 /usr/bin +#!/usr/bin/dh-exec +httpfs2-mt => /usr/bin/httpfs2 From ac859fd09bf9fed1efa4fbc34ae00f7ba82d1856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Thu, 28 Jul 2016 12:15:28 +0200 Subject: [PATCH 25/33] changeset: 92:01d9ffef99d4 user: Michal Suchanek date: Tue Jul 19 17:06:20 2016 +0200 summary: Fix gnutls build-dependency. --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 41bfd4e..a16b6ea 100644 --- a/debian/control +++ b/debian/control @@ -6,7 +6,7 @@ Build-Depends: debhelper (>= 9~), dh-exec, asciidoc, xmlto, libfuse-dev (>> 2.6), pkg-config, - libgnutls-dev (>= 2.10~), + libgnutls-dev (>= 2.10~) | libgnutls28-dev, Standards-Version: 3.8.4 Homepage: http://sourceforge.net/projects/httpfs/ From c649b2a3615468602707c7435b70da47e1006747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Tue, 9 Aug 2016 12:50:46 +0200 Subject: [PATCH 26/33] Handle non-fatal SSL errors. This includes renogotiation which was broken. Compile-tested. --- httpfs2.c | 52 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index ad95cbd..b6c943e 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -422,7 +422,7 @@ static int mempref(const char * mem, const char * pref, size_t size, int case_se #ifdef USE_SSL static void errno_report(const char * where); -static void ssl_error(int error, gnutls_session_t ss, const char * where); +static void ssl_error(ssize_t error, gnutls_session_t ss, const char * where); /* Functions to deal with gnutls_datum_t stolen from gnutls docs. * The structure does not seem documented otherwise. */ @@ -666,17 +666,17 @@ static void logfunc(int level, const char * str) fputs(str, stderr); } -static void ssl_error(int error, gnutls_session_t ss, const char * where) +static void ssl_error(ssize_t error, gnutls_session_t ss, const char * where) { struct_url * url = thread_setup(); const char * err_desc; if((error == GNUTLS_E_FATAL_ALERT_RECEIVED) || (error == GNUTLS_E_WARNING_ALERT_RECEIVED)) err_desc = gnutls_alert_get_name(gnutls_alert_get(ss)); else - err_desc = gnutls_strerror(error); + err_desc = gnutls_strerror((int)error); - fprintf(stderr, "%s: %s: %s: %d %s.\n", argv0, url->tname, where, error, err_desc); - errno = EIO; /* FIXME is this used anywhere? */ + fprintf(stderr, "%s: %s: %s: %zd %s.\n", argv0, url->tname, where, error, err_desc); + errno = EIO; } #endif @@ -1065,7 +1065,30 @@ int main(int argc, char *argv[]) return err ? err : 0; } +#ifdef USE_SSL +/* handle non-fatal SSL errors */ +int handle_ssl_error(struct_url *url, ssize_t * res) +{ + if (*res == GNUTLS_E_REHANDSHAKE) { + ssl_error(*res, url->ss, "Rehanshake SSL requested by server."); + if (gnutls_safe_renegotiation_status(url->ss)) { + *res = gnutls_handshake (url->ss); + return 1; + } else { + ssl_error(*res, url->ss, "Safe rehanshake not supported on this connection."); + return 0; + } + } + if (!gnutls_error_is_fatal((int)*res)) { + ssl_error(*res, url->ss, "Ignoring non-fatal SSL error."); + *res = 0; + return 1; + } + + return 0; +} +#endif /* * Socket operations that abstract ssl and keepalive as much as possible. @@ -1164,8 +1187,10 @@ static ssize_t read_client_socket(struct_url *url, void * buf, size_t len) { setsockopt(url->sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); #ifdef USE_SSL if (url->proto == PROTO_HTTPS) { - res = gnutls_record_recv(url->ss, buf, len); - if (res <= 0) ssl_error((int)res, url->ss, "read"); + do { + res = gnutls_record_recv(url->ss, buf, len); + } while ((res <= 0) && handle_ssl_error(url, &res)); + if (res <= 0) ssl_error(res, url->ss, "read"); } else #endif { @@ -1185,8 +1210,10 @@ write_client_socket(struct_url *url, const void * buf, size_t len) if (fd < 0) return -1; /*error hopefully reported by open*/ #ifdef USE_SSL if (url->proto == PROTO_HTTPS) { - res = gnutls_record_send(url->ss, buf, len); - if (res <= 0) ssl_error((int)res, url->ss, "write"); + do { + res = gnutls_record_send(url->ss, buf, len); + } while ((res <= 0) && handle_ssl_error(url, &res)); + if (res <= 0) ssl_error(res, url->ss, "write"); /* * It is suggested to retry GNUTLS_E_INTERRUPTED and GNUTLS_E_AGAIN * However, retrying only causes delay in practice. FIXME @@ -1325,7 +1352,7 @@ static int open_client_socket(struct_url *url) { #ifdef USE_SSL if ((url->proto) == PROTO_HTTPS) { /* Make SSL connection. */ - int r = 0; + ssize_t r = 0; const char * ps = "NORMAL"; /* FIXME allow user setting */ const char * errp = NULL; if (!url->ssl_initialized) { @@ -1336,7 +1363,7 @@ static int open_client_socket(struct_url *url) { if (!r) r = gnutls_certificate_set_x509_trust_file (url->sc, url->cafile, GNUTLS_X509_FMT_PEM); if (r>0) - fprintf(stderr, "%s: SSL init: loaded %i CA certificate(s).\n", argv0, r); + fprintf(stderr, "%s: SSL init: loaded %zi CA certificate(s).\n", argv0, r); if (r>0) r = 0; } if (!r) @@ -1360,7 +1387,8 @@ static int open_client_socket(struct_url *url) { /* alternative to gnutls_priority_set_direct: if (!r) gnutls_set_default_priority(url->ss); */ if (!r) r = gnutls_credentials_set(url->ss, GNUTLS_CRD_CERTIFICATE, url->sc); if (!r) gnutls_transport_set_ptr(url->ss, (gnutls_transport_ptr_t) (intptr_t) url->sockfd); - if (!r) r = gnutls_handshake (url->ss); /* FIXME gnutls_error_is_fatal is recommended here */ + if (!r) r = gnutls_handshake (url->ss); + do ; while ((r) && handle_ssl_error(url, &r)); if (r) { close(url->sockfd); if (errp) fprintf(stderr, "%s: invalid SSL priority\n %s\n %*s\n", argv0, ps, (int)(errp - ps), "^"); From 47ba62084dcb667c9603d9729cab8f6993fe5f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Tue, 9 Aug 2016 13:13:03 +0200 Subject: [PATCH 27/33] Convert ssl_error from gnutls_session to struct_url --- httpfs2.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index b6c943e..486c27c 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -422,7 +422,7 @@ static int mempref(const char * mem, const char * pref, size_t size, int case_se #ifdef USE_SSL static void errno_report(const char * where); -static void ssl_error(ssize_t error, gnutls_session_t ss, const char * where); +static void ssl_error(ssize_t error, struct_url * url, const char * where); /* Functions to deal with gnutls_datum_t stolen from gnutls docs. * The structure does not seem documented otherwise. */ @@ -568,7 +568,7 @@ verify_certificate_callback (gnutls_session_t session) ret = gnutls_certificate_verify_peers2 (session, &status); if (ret < 0) { - ssl_error(ret, session, "verify certificate"); + ssl_error(ret, url, "verify certificate"); return GNUTLS_E_CERTIFICATE_ERROR; } if (status & GNUTLS_CERT_INVALID) @@ -591,7 +591,7 @@ verify_certificate_callback (gnutls_session_t session) return GNUTLS_E_CERTIFICATE_ERROR; if (gnutls_x509_crt_init (&cert) < 0) { - ssl_error(ret, session, "verify certificate"); + ssl_error(ret, url, "verify certificate"); return GNUTLS_E_CERTIFICATE_ERROR; } cert_list = gnutls_certificate_get_peers (session, &cert_list_size); @@ -604,7 +604,7 @@ verify_certificate_callback (gnutls_session_t session) ret = gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER); if (ret < 0) { - ssl_error(ret, session, "parsing certificate"); + ssl_error(ret, url, "parsing certificate"); return GNUTLS_E_CERTIFICATE_ERROR; } if (!(url->ssl_connected)) if (!gnutls_x509_crt_print (cert, GNUTLS_CRT_PRINT_FULL, &data)) { @@ -637,7 +637,7 @@ verify_certificate_callback (gnutls_session_t session) if (!(url->ssl_connected)) fprintf(stderr, "Cert CN(%i): %s: %c\n", i, dn, match?'*':'X'); }} else - ssl_error(dn_ret, session, "getting cert subject data"); + ssl_error(dn_ret, url, "getting cert subject data"); if (dn) free(dn); if (dn_ret || !dn) break; @@ -666,12 +666,11 @@ static void logfunc(int level, const char * str) fputs(str, stderr); } -static void ssl_error(ssize_t error, gnutls_session_t ss, const char * where) +static void ssl_error(ssize_t error, struct_url * url, const char * where) { - struct_url * url = thread_setup(); const char * err_desc; if((error == GNUTLS_E_FATAL_ALERT_RECEIVED) || (error == GNUTLS_E_WARNING_ALERT_RECEIVED)) - err_desc = gnutls_alert_get_name(gnutls_alert_get(ss)); + err_desc = gnutls_alert_get_name(gnutls_alert_get(url->ss)); else err_desc = gnutls_strerror((int)error); @@ -1070,18 +1069,18 @@ int main(int argc, char *argv[]) int handle_ssl_error(struct_url *url, ssize_t * res) { if (*res == GNUTLS_E_REHANDSHAKE) { - ssl_error(*res, url->ss, "Rehanshake SSL requested by server."); + ssl_error(*res, url, "Rehanshake SSL requested by server."); if (gnutls_safe_renegotiation_status(url->ss)) { *res = gnutls_handshake (url->ss); return 1; } else { - ssl_error(*res, url->ss, "Safe rehanshake not supported on this connection."); + ssl_error(*res, url, "Safe rehanshake not supported on this connection."); return 0; } } if (!gnutls_error_is_fatal((int)*res)) { - ssl_error(*res, url->ss, "Ignoring non-fatal SSL error."); + ssl_error(*res, url, "Ignoring non-fatal SSL error."); *res = 0; return 1; } @@ -1190,7 +1189,7 @@ static ssize_t read_client_socket(struct_url *url, void * buf, size_t len) { do { res = gnutls_record_recv(url->ss, buf, len); } while ((res <= 0) && handle_ssl_error(url, &res)); - if (res <= 0) ssl_error(res, url->ss, "read"); + if (res <= 0) ssl_error(res, url, "read"); } else #endif { @@ -1213,7 +1212,7 @@ write_client_socket(struct_url *url, const void * buf, size_t len) do { res = gnutls_record_send(url->ss, buf, len); } while ((res <= 0) && handle_ssl_error(url, &res)); - if (res <= 0) ssl_error(res, url->ss, "write"); + if (res <= 0) ssl_error(res, url, "write"); /* * It is suggested to retry GNUTLS_E_INTERRUPTED and GNUTLS_E_AGAIN * However, retrying only causes delay in practice. FIXME @@ -1375,7 +1374,7 @@ static int open_client_socket(struct_url *url) { gnutls_global_set_log_function(&logfunc); } if (r) { - ssl_error(r, url->ss, "SSL init"); + ssl_error(r, url, "SSL init"); return -1; } @@ -1393,7 +1392,7 @@ static int open_client_socket(struct_url *url) { close(url->sockfd); if (errp) fprintf(stderr, "%s: invalid SSL priority\n %s\n %*s\n", argv0, ps, (int)(errp - ps), "^"); fprintf(stderr, "%s: %s:%d - ", argv0, url->host, url->port); - ssl_error(r, url->ss, "SSL connection failed"); + ssl_error(r, url, "SSL connection failed"); fprintf(stderr, "%s: %s: closing SSL socket.\n", argv0, url->tname); gnutls_deinit(url->ss); errno = EIO; From 499e0531fc76935abc4566d1970f3f3e183f279d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Wed, 10 Aug 2016 16:21:18 +0200 Subject: [PATCH 28/33] Fix non-fatal SSL error handling. The handler could loop on 0 return value. Don't call it on 0 and reject 0 in the handler. --- httpfs2.c | 44 +++++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index 486c27c..6e9f58d 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -423,6 +423,7 @@ static int mempref(const char * mem, const char * pref, size_t size, int case_se static void errno_report(const char * where); static void ssl_error(ssize_t error, struct_url * url, const char * where); +static void ssl_error_p(ssize_t error, struct_url * url, const char * where); /* Functions to deal with gnutls_datum_t stolen from gnutls docs. * The structure does not seem documented otherwise. */ @@ -666,7 +667,7 @@ static void logfunc(int level, const char * str) fputs(str, stderr); } -static void ssl_error(ssize_t error, struct_url * url, const char * where) +static void ssl_error_p(ssize_t error, struct_url * url, const char * where, const char * extra) { const char * err_desc; if((error == GNUTLS_E_FATAL_ALERT_RECEIVED) || (error == GNUTLS_E_WARNING_ALERT_RECEIVED)) @@ -674,7 +675,13 @@ static void ssl_error(ssize_t error, struct_url * url, const char * where) else err_desc = gnutls_strerror((int)error); - fprintf(stderr, "%s: %s: %s: %zd %s.\n", argv0, url->tname, where, error, err_desc); + fprintf(stderr, "%s: %s: %s: %s%zd %s.\n", argv0, url->tname, where, extra, error, err_desc); +} + +static void ssl_error(ssize_t error, struct_url * url, const char * where) +{ + ssl_error_p(error, url, where, ""); + /* FIXME try to decode errors more meaningfully */ errno = EIO; } #endif @@ -1066,21 +1073,36 @@ int main(int argc, char *argv[]) #ifdef USE_SSL /* handle non-fatal SSL errors */ -int handle_ssl_error(struct_url *url, ssize_t * res) +int handle_ssl_error(struct_url *url, ssize_t * res, where) { + /* do not handle success */ + if (!res) + return 0; + /* + * It is suggested to retry GNUTLS_E_INTERRUPTED and GNUTLS_E_AGAIN + * However, retrying only causes delay in practice. FIXME + */ + if ((*res == GNUTLS_E_INTERRUPTED) || (*res == GNUTLS_E_AGAIN)) + return 0; + if (*res == GNUTLS_E_REHANDSHAKE) { - ssl_error(*res, url, "Rehanshake SSL requested by server."); + fprintf(stderr, "%s: %s: %s: %zd %s.\n", argv0, url->tname, where, error, + "SSL rehanshake requested by server"); if (gnutls_safe_renegotiation_status(url->ss)) { *res = gnutls_handshake (url->ss); + if (*res) { + return 0; + } return 1; } else { - ssl_error(*res, url, "Safe rehanshake not supported on this connection."); + fprintf(stderr, "%s: %s: %s: %zd %s.\n", argv0, url->tname, where, error, + "safe rehandshake not supported on this connection"); return 0; } } if (!gnutls_error_is_fatal((int)*res)) { - ssl_error(*res, url, "Ignoring non-fatal SSL error."); + ssl_error_p(*res, url, where, "non-fatal SSL error "); *res = 0; return 1; } @@ -1188,7 +1210,7 @@ static ssize_t read_client_socket(struct_url *url, void * buf, size_t len) { if (url->proto == PROTO_HTTPS) { do { res = gnutls_record_recv(url->ss, buf, len); - } while ((res <= 0) && handle_ssl_error(url, &res)); + } while ((res < 0) && handle_ssl_error(url, &res, "read")); if (res <= 0) ssl_error(res, url, "read"); } else #endif @@ -1211,12 +1233,8 @@ write_client_socket(struct_url *url, const void * buf, size_t len) if (url->proto == PROTO_HTTPS) { do { res = gnutls_record_send(url->ss, buf, len); - } while ((res <= 0) && handle_ssl_error(url, &res)); + } while ((res < 0) && handle_ssl_error(url, &res, "write")); if (res <= 0) ssl_error(res, url, "write"); - /* - * It is suggested to retry GNUTLS_E_INTERRUPTED and GNUTLS_E_AGAIN - * However, retrying only causes delay in practice. FIXME - */ } else #endif { @@ -1387,7 +1405,7 @@ static int open_client_socket(struct_url *url) { if (!r) r = gnutls_credentials_set(url->ss, GNUTLS_CRD_CERTIFICATE, url->sc); if (!r) gnutls_transport_set_ptr(url->ss, (gnutls_transport_ptr_t) (intptr_t) url->sockfd); if (!r) r = gnutls_handshake (url->ss); - do ; while ((r) && handle_ssl_error(url, &r)); + do ; while ((r) && handle_ssl_error(url, &r, "opening SSL socket")); if (r) { close(url->sockfd); if (errp) fprintf(stderr, "%s: invalid SSL priority\n %s\n %*s\n", argv0, ps, (int)(errp - ps), "^"); From 28ce0c653cf9ead73867bb415af2cf9731d41701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Wed, 10 Aug 2016 16:39:14 +0200 Subject: [PATCH 29/33] Alwas set errno when returning from parse_header --- httpfs2.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index 6e9f58d..097bf93 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -1454,6 +1454,7 @@ parse_header(struct_url *url, const char * buf, size_t bytes, int seen_accept = 0, seen_length = 0, seen_close = 0; if (bytes <= 0) { + errno = EINVAL; return -1; } @@ -1495,6 +1496,7 @@ parse_header(struct_url *url, const char * buf, size_t bytes, close_client_force(url); http_report("redirect did not contain a Location header!", method, buf, 0); + errno = ENOENT; return -1; } @@ -1510,7 +1512,8 @@ parse_header(struct_url *url, const char * buf, size_t bytes, url->redirect_depth ++; if (url->redirect_depth > MAX_REDIRECTS) { fprintf(stderr, "%s: %s: server redirected %i times already. Giving up.", argv0, url->tname, MAX_REDIRECTS); - return -EIO; + errno = EIO; + return -1; } if (status == 301) { @@ -1525,8 +1528,10 @@ parse_header(struct_url *url, const char * buf, size_t bytes, free(tmp); } - if(res < 0) + if(res < 0) { + errno = EIO; return res; + } print_url(stderr, url); return -EAGAIN; @@ -1537,8 +1542,10 @@ parse_header(struct_url *url, const char * buf, size_t bytes, fprintf(stderr, "%s: %s: failed with status: %d%.*s.\n", argv0, method, status, (int)((end - ptr) - 1), ptr); if (!strcmp("HEAD", method)) fwrite(buf, bytes, 1, stderr); /*DEBUG*/ - errno = EIO; - if (status == 404) errno = ENOENT; + if (status == 404) + errno = ENOENT; + else + errno = EIO; return -1; } From 598c008dd420ea04a60bbfffbbdc56cdc6782361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Wed, 10 Aug 2016 16:45:09 +0200 Subject: [PATCH 30/33] Always set errno when returning from exchange() --- httpfs2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/httpfs2.c b/httpfs2.c index 097bf93..9440810 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -1688,6 +1688,8 @@ exchange(struct_url *url, char * buf, const char * method, errno_report("exchange: failed to send request"); /* DEBUG */ if (close_client_force(url) == -EAGAIN) goto req; + if (!errno) + errno = EIO; return res; } res = read_client_socket(url, buf, HEADER_SIZE); @@ -1712,6 +1714,8 @@ exchange(struct_url *url, char * buf, const char * method, errno_report("exchange: failed receving reply from server"); /* DEBUG */ if (close_client_force(url) == -EAGAIN) goto req; + if (!errno) + errno = EIO; return res; } else { bytes = (size_t)res; From 763ada02189abdf3aac86ea160ed80402d9bcf7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Such=C3=A1nek?= <787652+hramrach@users.noreply.github.com> Date: Wed, 10 Aug 2016 16:50:34 +0200 Subject: [PATCH 31/33] fix handle_ssl_error --- httpfs2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index 9440810..803c3f5 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -423,7 +423,7 @@ static int mempref(const char * mem, const char * pref, size_t size, int case_se static void errno_report(const char * where); static void ssl_error(ssize_t error, struct_url * url, const char * where); -static void ssl_error_p(ssize_t error, struct_url * url, const char * where); +static void ssl_error_p(ssize_t error, struct_url * url, const char * where, const char * extra); /* Functions to deal with gnutls_datum_t stolen from gnutls docs. * The structure does not seem documented otherwise. */ @@ -1073,7 +1073,7 @@ int main(int argc, char *argv[]) #ifdef USE_SSL /* handle non-fatal SSL errors */ -int handle_ssl_error(struct_url *url, ssize_t * res, where) +int handle_ssl_error(struct_url *url, ssize_t * res, const char *where) { /* do not handle success */ if (!res) @@ -1086,7 +1086,7 @@ int handle_ssl_error(struct_url *url, ssize_t * res, where) return 0; if (*res == GNUTLS_E_REHANDSHAKE) { - fprintf(stderr, "%s: %s: %s: %zd %s.\n", argv0, url->tname, where, error, + fprintf(stderr, "%s: %s: %s: %zd %s.\n", argv0, url->tname, where, *res, "SSL rehanshake requested by server"); if (gnutls_safe_renegotiation_status(url->ss)) { *res = gnutls_handshake (url->ss); @@ -1095,7 +1095,7 @@ int handle_ssl_error(struct_url *url, ssize_t * res, where) } return 1; } else { - fprintf(stderr, "%s: %s: %s: %zd %s.\n", argv0, url->tname, where, error, + fprintf(stderr, "%s: %s: %s: %zd %s.\n", argv0, url->tname, where, *res, "safe rehandshake not supported on this connection"); return 0; } From 4da2bb1befbe94865ae1a8c94c0b48a3f863505a Mon Sep 17 00:00:00 2001 From: Eugene Vorobev Date: Mon, 28 Nov 2011 14:41:51 +0200 Subject: [PATCH 32/33] Add option to take filename from HTTP header --- httpfs2.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/httpfs2.c b/httpfs2.c index 803c3f5..9061a9d 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -95,6 +95,8 @@ typedef struct url { int port; char * path; /*get path*/ char * name; /*file name*/ + char * filename; /*content file name*/ + int filename_from_header; /* take filename from HTTP header */ #ifdef USE_AUTH char * auth; /*encoded auth data*/ #endif @@ -256,7 +258,7 @@ static void httpfs_lookup(fuse_req_t req, fuse_ino_t parent, const char *name) e.attr_timeout = 1.0; e.entry_timeout = 1.0; - if (parent != 1 || strcmp(name, main_url.name) != 0){ + if (parent != 1 || strcmp(name, main_url.filename) != 0){ e.ino = 0; } else { e.ino = 2; @@ -315,7 +317,7 @@ static void httpfs_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, memset(&b, 0, sizeof(b)); dirbuf_add(req, &b, ".", 1); dirbuf_add(req, &b, "..", 1); - dirbuf_add(req, &b, main_url.name, 2); + dirbuf_add(req, &b, main_url.filename, 2); reply_buf_limited(req, b.p, b.size, off, size); free(b.p); } @@ -373,6 +375,8 @@ static void httpfs_read(fuse_req_t req, fuse_ino_t ino, size_t size, url->req_buf = malloc(size); } + fprintf(stderr, "httpfs_read: size: %lld b (%lld kb), off: %lld b (%lld kb)\n", (long long)url->req_buf_size, (long long)(url->req_buf_size/1024), (long long)off, (long long)(off/1024)); + if((res = get_data(url, off, size)) < 0){ assert(errno); fuse_reply_err(req, errno); @@ -751,6 +755,7 @@ static void print_url(FILE *f, const struct_url * url) #endif } fprintf(f, "file name: \t%s\n", url->name); + fprintf(f, "content file name: \t%s\n", url->filename); fprintf(f, "host name: \t%s\n", url->host); fprintf(f, "port number: \t%d\n", url->port); fprintf(f, "protocol: \t%s\n", protocol); @@ -873,6 +878,7 @@ static int parse_url(char * _url, struct_url* res, enum url_flags flag) } } else assert(res->name); + res->filename = res->name; return res->proto; } @@ -898,6 +904,7 @@ static void usage(void) #ifdef RETRY_ON_RESET fprintf(stderr, "\t -r \tnumber of times to retry connection on reset\n\t\t(default: %i)\n", RESET_RETRIES); #endif + fprintf(stderr, "\t -n \ttake filename from HTTP header (default: from url)\n"); fprintf(stderr, "\t -t \tset socket timeout in seconds (default: %i)\n", TIMEOUT); fprintf(stderr, "\tmount-parameters should include the mount point\n"); } @@ -943,6 +950,8 @@ int main(int argc, char *argv[]) fork_terminal = 0; } break; + case 'n': main_url.filename_from_header = 1; + break; #ifdef USE_SSL case '2': main_url.md2 = GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2; break; @@ -1553,6 +1562,7 @@ parse_header(struct_url *url, const char * buf, size_t bytes, char * accept = "Accept-Ranges: bytes"; char * range = "Content-Range: bytes"; char * date = "Last-Modified: "; + char * content_disposition_str = "Content-Disposition: attachment; filename=\""; char * close = "Connection: close"; struct tm tm; while(1) @@ -1599,6 +1609,13 @@ parse_header(struct_url *url, const char * buf, size_t bytes, seen_accept = 1; continue; } + if( url->filename_from_header ){ + if(mempref(ptr, content_disposition_str, (size_t)(end - ptr), 0) ){ + url->filename = (char *)ptr + strlen(content_disposition_str); + url->filename = strndup(url->filename, (size_t)(end - url->filename) - 1); + continue; + } + } if( mempref(ptr, date, (size_t)(end - ptr), 0) ){ memset(&tm, 0, sizeof(tm)); if(!strptime(ptr + strlen(date), From 8c40fff1872370f73bb591c46a3350e7704df568 Mon Sep 17 00:00:00 2001 From: Daniel Gimpelevich Date: Mon, 28 Feb 2022 20:11:28 -0800 Subject: [PATCH 33/33] Minor fixes --- Makefile | 4 ++-- debian/changelog | 22 +++++++++++++++++++++- debian/control | 6 +++--- debian/source/format | 1 + httpfs2.c | 4 ++-- 5 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 debian/source/format diff --git a/Makefile b/Makefile index d3db29c..4860019 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ MAIN_CFLAGS := -g -Os -Wall $(shell pkg-config fuse --cflags) -MAIN_CPPFLAGS := -Wall -Wno-unused-function -Wconversion -Wtype-limits -DUSE_AUTH -D_XOPEN_SOURCE=700 -D_ISOC99_SOURCE -THR_CPPFLAGS := -DUSE_THREAD +MAIN_CPPFLAGS := -Wall -Wno-unused-function -Wconversion -Wtype-limits -DUSE_AUTH -D_XOPEN_SOURCE=700 -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 +THR_CPPFLAGS := -DUSE_THREAD -pthread THR_LDFLAGS := -lpthread GNUTLS_VERSION := 2.10 MAIN_LDFLAGS := $(shell pkg-config fuse --libs | sed -e s/-lrt// -e s/-ldl// -e s/-pthread// -e "s/ / /g") diff --git a/debian/changelog b/debian/changelog index d4bd722..690cc95 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,12 @@ +httpfs2 (0.1.5+nmu1) unstable; urgency=medium + + * Non-maintainer upload. + * Use source format 3.0 (native). + * Fix CPPFLAGS and large file support. + * Add patch from Eugene Vorobev to take filename from HTTP header. + + -- Daniel Gimpelevich Mon, 28 Feb 2022 21:23:03 -0800 + httpfs2 (0.1.5-2) UNRELEASED; urgency=medium * New upstream release: @@ -5,7 +14,7 @@ httpfs2 (0.1.5-2) UNRELEASED; urgency=medium - miscellaneous bug fixes (Closes: #698179, #716022, #729027) - HTTP redirect support - * install multithreaded version + * Install multithreaded version. -- Michal Suchanek Fri, 15 Jul 2016 17:16:08 +0200 @@ -19,6 +28,17 @@ httpfs2 (0.1.5-1) unstable; urgency=low -- Michal Suchanek Fri, 31 Aug 2012 13:01:28 +0200 +httpfs2 (0.1.4-1.1) unstable; urgency=medium + + * Non-maintainer upload. + * Use source format 3.0 (quilt). Closes: #651312 + * Recommend fuse instead of fuse-utils. Closes: #698179 + * Add patch from Ubuntu to fix FTBFS with libc 2.22. Closes: #811890 + * Add patch from Ubuntu to fix linking with --as-needed. Closes: #641728 + * Bump Standards-Version to 3.9.8, no changes needed. + + -- Mattia Rizzolo Fri, 10 Mar 2017 13:27:02 +0100 + httpfs2 (0.1.4-1) unstable; urgency=low * New upstream release: diff --git a/debian/control b/debian/control index a16b6ea..01c5b3c 100644 --- a/debian/control +++ b/debian/control @@ -1,13 +1,13 @@ Source: httpfs2 Section: web Priority: extra -Maintainer: Michal Suchanek +Maintainer: Michal Suchanek Build-Depends: debhelper (>= 9~), dh-exec, asciidoc, xmlto, libfuse-dev (>> 2.6), pkg-config, libgnutls-dev (>= 2.10~) | libgnutls28-dev, -Standards-Version: 3.8.4 +Standards-Version: 3.9.8 Homepage: http://sourceforge.net/projects/httpfs/ Package: httpfs2 @@ -22,7 +22,7 @@ Description: FUSE filesystem for mounting files from http servers Package: httpfs2-ssl Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, -Recommends: fuse-utils +Recommends: fuse-utils | fuse (>= 2.9.3~) Description: FUSE filesystem for mounting files from http servers (SSL enabled) httpfs2 is a FUSE based filesystem for mounting http or https URLS as files in the filesystem. There is no notion of listable directories in http so only a diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..89ae9db --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/httpfs2.c b/httpfs2.c index 9061a9d..a210f95 100644 --- a/httpfs2.c +++ b/httpfs2.c @@ -226,7 +226,7 @@ static int httpfs_stat(fuse_ino_t ino, struct stat *stbuf) fprintf(stderr, "%s: %s: stat()\n", argv0, url->tname); /*DEBUG*/ stbuf->st_mode = S_IFREG | 0444; stbuf->st_nlink = 1; - return (int) get_stat(url, stbuf); + return -(get_stat(url, stbuf) < 0); } break; @@ -1568,7 +1568,7 @@ parse_header(struct_url *url, const char * buf, size_t bytes, while(1) { ptr = end+1; - if( !(ptr < buf + (header_len - 4))){ + if( !(ptr < buf + (header_len - 4)) ){ if(seen_accept && seen_length){ if(url->sock_type == SOCK_OPEN && !seen_close) url->sock_type = SOCK_KEEPALIVE;