Sophie

Sophie

distrib > Mageia > 7 > aarch64 > by-pkgid > 14793770b3f4b8d08296008cfe619d47 > files > 1

httpfs-2.06.07.10-3.mga7.src.rpm

--- ./httpfs.c.orig	2006-07-12 00:26:41.000000000 +0400
+++ ./httpfs.c	2012-11-18 21:33:35.000000000 +0400
@@ -1,91 +1,74 @@
+
 /*
- * HTTPFS: import a file from a web server to local file system
- * the main use is, to mount an iso on a web server with loop device
- *
- * depends on:
- * FUSE: Filesystem in Userspace
- * Copyright (C) 2001-2006  Miklos Szeredi <miklos@szeredi.hu>
- *
+ * HTTPFS: http filesystem using FUSE
  * This program can be distributed under the terms of the GNU GPL.
- *
- */
 
-/* 
- * This 'beam me up, Scotty'-branch of httpfs tries to achieve,
- * that the mount-point-folder behaves as before.
- * But how can you access the original folder after the mount?
- * Answer comes from FuseCompress:
- *	Open the folder before the mount,
- *	keep it open all the time,
- *	make a chdir to it
- *	and always use a relative path.
- * It suffices not to chdir in main() and it's unnecessary to
- * do it in every function. httpfs_init is the right place.
- */
+   Authors:
+	Marion Raven (httpfs code)
+	Tomas M (all the further updates)
+	
+	Anton Goroshkin <http://magos-linux.ru>
 
+ */
 
 #include <fuse.h>
+#include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/dir.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
 #include <netdb.h>
-#include <time.h>
-
-#ifdef USE_SSL
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#endif
 
 #define TIMEOUT 30
-#define VERSION "2.06.07.10"
-
-static char* argv0;
-static char* argv1;
-static char* argv2;
-static long long int file_size;
-static int protocol;
-static char host[1000];
-static unsigned short port;
-static char* file_name;
-
-
-static char httpfs_path[256];
-static int targetFd;
+#define BUFSIZE 1024*8
+#define BIGBUFSIZE 64*BUFSIZE
+#define RESP_STATUS_LEN 12 // sizeof "HTTP/1.1 200"
+#define VERSION "for MagOS Linux"
+
+#define MIN(a,b) \
+    ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+        _a < _b ? _a : _b; })
+
+static char *myself;
+static char *arg_url;
+static char *arg_mnt;
+FILE * fou;
+
+static char http_auth[BUFSIZE];
+static char http_host[BUFSIZE];
+static char http_base[BUFSIZE];
+static char http_path[BUFSIZE];
+static char http_file[BUFSIZE];
+static unsigned short int http_port;
+
+//static char host[BUFSIZE];
+//static unsigned short port;
+//static char *file_name;
+//static char httpfs_path[BUFSIZE];
+//static char http_base[BUFSIZE];
 static int sockfd;
-
-/* Protocol symbols. */
-#define PROTO_HTTP 0
-#ifdef USE_SSL
-#define PROTO_HTTPS 1
-#endif
+static char *http = "http://";
 
 #ifdef USE_AUTH
-static char auth_buf[1000];
-
+/*
 static char b64_encode_table[64] = {
-    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',  /* 0-7 */
-    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',  /* 8-15 */
-    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',  /* 16-23 */
-    'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',  /* 24-31 */
-    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',  /* 32-39 */
-    'o', 'p', 'q', 'r', 's', 't', 'u', 'v',  /* 40-47 */
-    'w', 'x', 'y', 'z', '0', '1', '2', '3',  /* 48-55 */
-    '4', '5', '6', '7', '8', '9', '+', '/'   /* 56-63 */
+    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',  // 0-7
+    'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',  // 8-15
+    'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',  // 16-23
+    'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',  // 24-31
+    'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',  // 32-39
+    'o', 'p', 'q', 'r', 's', 't', 'u', 'v',  // 40-47
+    'w', 'x', 'y', 'z', '0', '1', '2', '3',  // 48-55
+    '4', '5', '6', '7', '8', '9', '+', '/'   // 56-63
 };
-    
-/* Do base-64 encoding on a hunk of bytes.   Return the actual number of
-** bytes generated.  Base-64 encoding takes up 4/3 the space of the original,
-** plus a bit for end-padding.  3/2+5 gives a safe margin.
-*/
-static int b64_encode(unsigned char* ptr, int len, char* space, int size) {
+
+// Do base-64 encoding on a hunk of bytes.   Return the actual number of
+// bytes generated.  Base-64 encoding takes up 4/3 the space of the original,
+// plus a bit for end-padding.  3/2+5 gives a safe margin.
+//
+
+static int b64_encode(char* ptr, int len, char* space, int size) {
     int ptr_idx;
     unsigned char c = 0;
     unsigned char d = 0;
@@ -117,7 +100,7 @@
     if (phase != 0) {
 	space[space_idx++] = b64_encode_table[d];
 	if (space_idx == size) return space_idx;
-	/* Pad with ='s. */
+	// Pad with ='s.
 	while (phase++ > 0) {
 	    space[space_idx++] = '=';
 	    if (space_idx == size) return space_idx;
@@ -126,79 +109,60 @@
     }
     return space_idx;
 }
-
+*/
 #endif /* USE_AUTH */
 
 /*
- * Function yields host, file, port and auth_buf
- * (auth_buf is global)
- * Besides protocol is returned
- * (-1 in case of error)
+ * Function sets global variables http_host, http_path, http_file, http_port, and http_auth
+ * url = http://user:password@domain.com:80/path/file.dat
+ * If parsing fails, returns -1
  */
+static int parse_url(char *url) {
+    char *pos, *auth, *port, *path, *file;
 
-static int parseURL(char* url, char* host, char** ptrfile, unsigned short* port) {
-    int host_len, protocol, proto_len;
-    char* file;
-	
-    char* http = "http://";
-#ifdef USE_SSL
-    char* https = "https://";
-#endif /* USE_SSL */
-
-
-    if (url == NULL) {
-	(void) fprintf(stderr, "%s: null URL\n", argv0);
-        return -1;
-    }
-    if (strncmp(http, url, strlen(http)) == 0) {
-	proto_len = strlen(http);
-	protocol = PROTO_HTTP;
-	*port = 80;	
-#ifdef USE_SSL
-    } else if (strncmp(https, url, strlen(https)) == 0) {
-	proto_len = strlen(https);
-	protocol = PROTO_HTTPS;
-	*port = 443;
-#endif /* USE_SSL */
+    memset(http_auth,0,BUFSIZE);
+    memset(http_host,0,BUFSIZE);
+    memset(http_base,0,BUFSIZE);
+    memset(http_path,0,BUFSIZE);
+    memset(http_file,0,BUFSIZE);
+
+    // http part is optional
+    pos = url + (strcasestr(url, http) ? strlen(http) : 0);
+
+    auth = strchr(pos, '@');
+    if (auth != NULL) {
+	fprintf(stderr,"user auth not supported yet, ignored");
+	// http_auth = "user:pass"; // fix this
+	pos = auth + 1;
+    }
+
+    path = strchr(pos, '/');
+    port = strchr(pos, ':');
+
+    if (port < path && port != NULL) { // a semicolon is sooner than slash for path - that specifies port number
+	http_port = (unsigned short) atoi(port + 1);
+	strncpy(http_host, pos, port - pos);
     } else {
-	(void) fprintf(stderr, "%s: non-http URL\n", argv0);
-        return -1;
+	http_port = 80;
+	strncpy(http_host, pos, path - pos);
     }
 
-#ifdef USE_AUTH
-    /* Get user and password */
-    auth_buf[0] = '\0';
-    for (file = url + proto_len; *file != '\0' && *file != '/'; ++file) {
-	if (*file == '@') {
-	    auth_buf[b64_encode(url + proto_len, file - url - proto_len, auth_buf, sizeof(auth_buf))] = '\0';
-	    proto_len = file - url + 1;
-	    break;
-	}
-    }
-#endif /* USE_AUTH */
-    
-    /* Get the host name. */
-    for (file = url + proto_len; *file != '\0' && *file != ':' && *file != '/'; ++file)
-	;
-    host_len = file - url - proto_len;
-    strncpy(host, url + proto_len, host_len);
-    host[host_len] = '\0';
-
-    /* Get port number. */
-    if (*file == ':') {
-	*port = (unsigned short) atoi(++file);
-	for (; *file != '\0' && *file != '/'; ++file)
-	    ;
+    if (path != NULL) {
+//	strncpy(http_host, pos, path - pos);
+	file = strrchr(path, '/');
+	strncpy(http_path, path, file == path ? 1 : file - path);
+	strncpy(http_file, file + 1, strlen(file) - 1);
+    } else {
+	strncpy(http_host, pos, strlen(pos));
+	http_path[0]='/';
     }
-    
-    /* Get the file name. */
-    if (*file == '\0')
-	file = "/";
-    
-    *ptrfile = file;
-    return protocol;
-}
 
+    strncpy(http_base, http, strlen(http));
+    strncpy(http_base + strlen(http), http_host, strlen(http_host));
+    if (strcmp(http_path, "/") != 0) strncpy(http_base + strlen(http_base), http_path, strlen(http_path));
+
+    return 1;
+}
 
 /* 
  * Function yields either a 'connected' socket for
@@ -207,758 +171,412 @@
  * hostname is something like 'www.tmtd.de' or 192.168.0.86
  * port is expected in machine order (not net order)
  *
- * ((Flonix  defines USE_IPV6))
- * 
 */
 
-#if defined(AF_INET6) && defined(IN6_IS_ADDR_V4MAPPED)
-#define USE_IPV6
-#endif
-
-static int open_client_socket(char* hostname, unsigned short port) {
-#ifdef USE_IPV6
-    struct addrinfo hints;
-    char portstr[10];
-    int gaierr;
-    struct addrinfo* ai;
-    struct addrinfo* aiv4;
-    struct addrinfo* aiv6 = 0;
-    struct sockaddr_in6 sa;
-#else /* USE_IPV6 */
+static int open_client_socket() {
+    int fd;
     struct hostent *he;
     struct sockaddr_in sa;
-#endif /* USE_IPV6 */
-    int sa_len, sock_family, sock_type, sock_protocol;
-    int sockfd;
-
-    (void) memset((void*) &sa, 0, sizeof(sa));
-
-#ifdef USE_IPV6
-    (void) memset(&hints, 0, sizeof(hints));
-    hints.ai_family = PF_UNSPEC;
-    hints.ai_socktype = SOCK_STREAM;
-    (void) snprintf(portstr, sizeof(portstr), "%d", (int) port);
-    if ((gaierr = getaddrinfo(hostname, portstr, &hints, &ai)) != 0) {
-	(void) fprintf(stderr, "%s: getaddrinfo %s - %s\n", argv0, hostname, gai_strerror(gaierr));
-	return -1;
-    }
-
-    /* Find the first IPv4 and IPv6 entries. */
-    for (aiv4 = ai; aiv4 != NULL; aiv4 = aiv4->ai_next) {
-	if (aiv4->ai_family == AF_INET)
-	    break;
-	if ((aiv4->ai_family == AF_INET6) && (aiv6 == NULL))
-	    aiv6 = aiv4;
-    }
+    struct timeval timeout;
 
-    /* If there's an IPv4 address, use that, otherwise try IPv6. */
-    if (aiv4 == NULL) 
-	    aiv4 = aiv6;
-    if (aiv4 == NULL) {
-	(void) fprintf(stderr, "%s: no valid address found for host %s\n", argv0, hostname);
-	return -1;
-    }
-    if (sizeof(sa) < aiv4->ai_addrlen) {
-	(void) fprintf(stderr, "%s - sockaddr too small (%lu < %lu)\n", hostname, (unsigned long) sizeof(sa), (unsigned long) aiv4->ai_addrlen);
+    he = gethostbyname(http_host);
+    if (he == NULL) {
+	fprintf(stderr, "%s: unknown host - %s port=%d\n", myself, http_host,http_port);
 	return -1;
     }
-    sock_family = aiv4->ai_family;
-    sock_type = aiv4->ai_socktype;
-    sock_protocol = aiv4->ai_protocol;
-    sa_len = aiv4->ai_addrlen;
-    (void) memmove(&sa, aiv4->ai_addr, sa_len);
-    freeaddrinfo(ai);
 
-#else /* USE_IPV6 */
+    memset((void*) &sa, 0, sizeof(sa));
+    sa.sin_family = he->h_addrtype;
+    memmove(&sa.sin_addr, he->h_addr, he->h_length);
+    sa.sin_port = htons(http_port);
 
-    he = gethostbyname(hostname);
-    if (he == NULL) {
-	(void) fprintf(stderr, "%s: unknown host - %s\n", argv0, hostname);
-	return -1;
-    }
-    sock_family = sa.sin_family = he->h_addrtype;
-    sock_type = SOCK_STREAM;
-    sock_protocol = 0;
-    sa_len = sizeof(sa);
-    (void) memmove(&sa.sin_addr, he->h_addr, he->h_length);
-    sa.sin_port = htons(port);
-
-#endif /* USE_IPV6 */
-
-    sockfd = socket(sock_family, sock_type, sock_protocol);
-    if (sockfd < 0) {
-	(void) fprintf(stderr, "%s: couldn't get socket, got errno: %u\n", argv0, errno);
+    fd = socket(sa.sin_family, SOCK_STREAM, 0);
+    if (fd < 0) {
+	fprintf(stderr, "%s: couldn't get socket\n", myself);
 	return -1;
     }
-    if (connect(sockfd, (struct sockaddr*) &sa, sa_len) < 0) {
-	(void) fprintf(stderr, "%s: couldn't connect socket, got errno: %u\n", argv0, errno);
+    if (connect(fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
+	fprintf(stderr, "%s: couldn't connect socket\n", myself);
 	return -1;
     }
-    return sockfd;
-}
-
-/* 
- * Function uses HEAD-HTTP-Request
- * to determine the file size
- * This is done only once
- */
-
-int getSize() {
-#ifdef USE_SSL
-    SSL_CTX* ssl_ctx;
-    SSL* ssl;
-#endif
-    char buf[1000];
-    char* b;
-    struct timeval timeout;
-    int bytes, status;
-
-#ifdef USE_SSL
-    if (protocol == PROTO_HTTPS) {
-	/* Make SSL connection. */
-	int r;
-	SSL_load_error_strings();
-	SSLeay_add_ssl_algorithms();
-	ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-	ssl = SSL_new(ssl_ctx);
-	SSL_set_fd(ssl, sockfd);
-	r = SSL_connect(ssl);
-	if (r <= 0) {
-	    (void) fprintf(stderr, "%s: %s:%d - SSL connection failed - %d\n", argv0, host, port, r);
-	    ERR_print_errors_fp(stderr);
-	    exit(1);
-	}
-    }
-#endif
-
-    /* Build request buffer, starting with the HEAD. */
-
-    bytes = snprintf(buf, sizeof(buf), "HEAD %s HTTP/1.1\r\nHost: %s\r\n", file_name, host);
-#ifdef USE_AUTH
-    if ( *auth_buf != '\0' )
-	bytes += snprintf(&buf[bytes], sizeof(buf) - bytes, "Authorization: Basic %s\r\n", auth_buf);
-#endif
-    bytes += snprintf(&buf[bytes], sizeof(buf) - bytes, "\r\n");
-
-    /* Now actually send it. */
-#ifdef USE_SSL
-    if (protocol == PROTO_HTTPS)
-	(void) SSL_write(ssl, buf, bytes);
-    else
-#endif
-    (void) write(sockfd, buf, bytes);
 
+    // set socket timeout
     timeout.tv_sec = TIMEOUT;
     timeout.tv_usec = 0;
-    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+    setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
 
-#ifdef USE_SSL
-    if (protocol == PROTO_HTTPS)
-	bytes = SSL_read(ssl, buf, sizeof(buf));
-    else
-#else
-    bytes = read(sockfd, buf, sizeof(buf));
-#endif
-    if (bytes <= 0) {
-	fprintf(stderr, "%s: HEAD (read) failed\n", argv0);
-	return -1;
-    }
-#ifdef USE_SSL
-    if (protocol == PROTO_HTTPS) {
-	SSL_free(ssl);
-	SSL_CTX_free(ssl_ctx);
-    }
-#endif
-
-    (void) sscanf(buf, "HTTP/1.1 %d ", &status);
-    if (status != 200) {
-	fprintf(stderr, "%s: HEAD (read) failed with Status %d\n", argv0, status);
-	return -1;
-    }
-    b = strstr(buf,"Content-Length:");
-    if (b == NULL) {
-	fprintf(stderr, "%s: HEAD-Reply didn't contain Content-Length\n", argv0);
-	return -1;
-    }
-    file_size = atoll(b+16);
-    return 0;
+    return fd;
 }
 
-/* 
- * HttpGet does all the magic
- * a GET-Request with Range-Header
- * allows to read arbitrary bytes
- */
-
-int HttpGet(off_t start, size_t size, char * destination) {
-#ifdef USE_SSL
-    SSL_CTX* ssl_ctx;
-    SSL* ssl;
-#endif
-    char buf[1000];
-    char* b;
-    size_t end = start + size - 1;
-    struct timeval timeout;
-    int bytes, status;
+// return relative URL against the http_base
+// compare case insensitive
+char *relative_url(char *url) {
+    if (strncasecmp(url, http_base, strlen(http_base)) == 0) url += strlen(http_base);
+    if (strncasecmp(url, http, strlen(http)) == 0) url += strlen(url);
+    return url;
+}
 
-#ifdef USE_SSL
-    if (protocol == PROTO_HTTPS) {
-	/* Make SSL connection. */
-	int r;
-	SSL_load_error_strings();
-	SSLeay_add_ssl_algorithms();
-	ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-	ssl = SSL_new(ssl_ctx);
-	SSL_set_fd(ssl, sockfd);
-	r = SSL_connect(ssl);
-	if (r <= 0) {
-	    (void) fprintf(stderr, "%s: %s:%d - SSL connection failed - %d\n", argv0, host, port, r);
-	    ERR_print_errors_fp(stderr);
-	    exit(1);
-	}
-    }
-#endif
+/*
+ * A generic sendRequest function
+ * which handles all cases when connection no more exists
+ */
 
-    /* Build request buffer, starting with the GET. */
+static int sendRequest(const char *method, const char *path, off_t start, off_t end)
+{
+    char buf[BUFSIZE];
+    char tmp[RESP_STATUS_LEN];
+    char *pos;
+    int bytes;
+    int status;
+
+    // build the request buffer
+    memset(buf, 0, sizeof(buf));
+    bytes = snprintf(buf, sizeof(buf), "%s %s%s HTTP/1.1\r\nHost: %s\r\n", method, strcmp(http_path,"/") == 0 ? "" : http_path, path, http_host);
+
+    // keep the connection alive if requested
+    bytes += snprintf(&buf[bytes], sizeof(buf) - bytes, "Connection: Keep-Alive\r\n");
+
+    // handle HTTP_RANGE if needed
+    if (start > 0 || end > 0) {
+    	bytes += snprintf(&buf[bytes], sizeof(buf) - bytes, "Range: bytes=%llu-%llu\r\n", (unsigned long long) start, (unsigned long long) end);
+    }
+
+    // add authentication string if needed
+    #ifdef USE_AUTH
+    if ( *http_auth != '\0' )
+        bytes += snprintf(&buf[bytes], sizeof(buf) - bytes, "Authorization: Basic %s\r\n", http_auth);
+    #endif
 
-    bytes = snprintf(buf, sizeof(buf), "GET %s HTTP/1.1\r\nHost: %s\r\n", file_name, host);
-    bytes += snprintf(&buf[bytes], sizeof(buf) - bytes, "Range: bytes=%llu-%llu\r\n", (unsigned long long) start, (unsigned long long) end);
-#ifdef USE_AUTH
-    if ( *auth_buf != '\0' )
-	bytes += snprintf(&buf[bytes], sizeof(buf) - bytes, "Authorization: Basic %s\r\n", auth_buf);
-#endif
+    // finally send empty line so server can understnad it's all
     bytes += snprintf(&buf[bytes], sizeof(buf) - bytes, "\r\n");
+    fprintf(stderr,"------------- request -------------\n%s\n",buf);
+    for (;;)
+    {
+        // write request to socket and read first 12 bytes of response
+        write(sockfd, buf, bytes);
+	memset(tmp, 0, sizeof(tmp));
+        status = read(sockfd, tmp, sizeof(tmp));
+
+	if (status > 0) {
+	    // parse real status code
+	    sscanf(tmp, "HTTP/1.1 %d", &status);
+
+	    // handle HTTP redirect (status code 3xx with Location: header)
+	    if (status > 300 && status < 400) {
+    		read(sockfd, buf, sizeof(buf)); // hopefully we get enough data here
+		pos = strstr(buf,"Location:");
+		if (pos != NULL) {
+		    pos[strcspn(pos, "\n\r")] = '\0';
+		    pos = relative_url(pos+10); // 10 = strlen("Location: ")
+		    if (strlen(pos) == 0) return 404;
+		    close(sockfd);
+		    return sendRequest(method, pos, start, end);
+    		}
+	    }
 
-    /* Now actually send it. */
-#ifdef USE_SSL
-    if (protocol == PROTO_HTTPS)
-	(void) SSL_write(ssl, buf, bytes);
-    else
-#endif
-    (void) write(sockfd, buf, bytes);
-
-    timeout.tv_sec = TIMEOUT;
-    timeout.tv_usec = 0;
-    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
+	    if (status >= 100 && status <= 999) {
+        	return status;
+    	    }
+        }
+
+        // if we got so far, we were unable to read from sockfd. Reconnect.
+	close(sockfd);
+        sockfd = open_client_socket();
+    }
+}
 
+static off_t getSize(const char * path) {
+    char buf[BUFSIZE];
+    char* pos;
+    int status;
+
+    memset(buf, 0, sizeof(buf));
+    status = sendRequest("HEAD",path,0,0);
+    read(sockfd, buf, sizeof(buf));
+//    fprintf(fou,"=============HEAD start=========\n%s\n=============HEAD end=========\n",buf);
+    
+    pos = strstr(buf,"Accept-Ranges:");
+    if (pos == NULL || status != 200) return -1;
+    pos = strstr(buf,"Content-Length:");
+    if (pos == NULL || status != 200) return -1;
+    return atoll(pos+16);
+}
+
+static int httpGet(const char * path, off_t start, size_t size, char * destination, off_t maxRange) {
+    char buf[BUFSIZE];
+    char *pos;
+//    char *posa;
+    int b, bytes, status, c;
+    off_t end;
+
+    end = start + size - 1;
+    if (end > maxRange) end = maxRange;
+    if (start > end) start = end;
+
+    memset(buf, 0, sizeof(buf));
+    status = sendRequest("GET", path, start, end);
+    if (status >= 300) return -1;
+    bytes = read(sockfd, buf, sizeof(buf));
 
-#ifdef USE_SSL
-    if (protocol == PROTO_HTTPS)
-	bytes = SSL_read(ssl, buf, sizeof(buf));
-    else
-#else
-	bytes = read(sockfd, buf, sizeof(buf));
-#endif
-    if (bytes <= 0) {
-	fprintf(stderr, "%s: GET (read) failed with bytes= %d\n", argv0, bytes);
-	return bytes;
-    }
-    (void) sscanf(buf, "HTTP/1.1 %d ", &status);
-    if ((status != 200) && (status != 206)) {
-	fprintf(stderr, "%s: GET (read) failed with Status %d\n", argv0, status);
-	return -1;
-    }
-    b = strstr(buf,"Content-Length:");
-    if (b == NULL) {
-	fprintf(stderr, "%s: GET-Reply didn't contain Content-Length\n", argv0);
-	return -1;
-    }
-    if (atoll(b+16) != size) {
- 	fprintf(stderr, "%s: GET didn't yield whole piece\n", argv0);
-	size = (size_t) atoll(b+16);
+    // If the response doesn't contain all headers ended by \r\n\r\n,
+    // read more data. This should be rather handled by select() syscall,
+    // but I do not know how to use it yet.
+    b = 1;
+    while (strstr(buf,"\r\n\r\n") == NULL && b > 0) {
+        b = read(sockfd, buf + bytes, sizeof(buf) - bytes);
+        bytes += b;
+    }
+
+//    posa = strstr(buf,"Accept-Ranges:");
+    pos = strstr(buf,"Content-Length:");
+    if ((pos == NULL)) {
+	/*
+	 * HTTP 1.1 specification states that if the response doesn't 
+	 * specify Content-Length, Transfer-Encoding is always Chunked.
+	 * For that reason, we assume chunks here. We will read only
+	 * ONE chunk of data here, it should be enough for us.
+	 *
+	 * This part of httpGet is called by httpfs_readdir(), it should
+	 * never happen to jump here in httpfs_read()
+	 */
+    	    size_t chunksize = 0;
+    	    pos = strstr(buf,"\r\n\r\n")+4;
+	    b = 1; // make sure we have at least one line of data in buffer
+	    while ( strstr(pos,"\r\n") == NULL && b > 0 ) {
+	        b = read(sockfd, buf + bytes, sizeof(buf) - bytes);
+	        bytes += b;
+	    }
+	    sscanf(pos, "%x", &chunksize);
+	    if (size > chunksize) size = chunksize;
+    	    pos = strstr(pos,"\r\n")+2;
+	    c = 1; // close connection at the end - to drop other chunks
+    }
+    else {
+	size = (size_t) atoll(pos+16);
+        pos = strstr(buf,"\r\n\r\n")+4;
+        c = 0; // keep connection alive
     }
-    b = strstr(buf,"\r\n\r\n")+4;
 
-    
-    bytes -= (b - buf);
-    memcpy(destination, b, bytes);
+    // copy bytes from the current response to destination
+    bytes -= (pos - buf);
+    if (bytes < 0) return 0;
+    memcpy(destination, pos, bytes);
     size -= bytes;
+
+    // read the rest of the response directly to address destination+bytes
     for (; size > 0; size -= bytes) {
 	destination += bytes;
-	timeout.tv_sec = TIMEOUT;
-	timeout.tv_usec = 0;
-	setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
-#ifdef USE_SSL
-	if (protocol == PROTO_HTTPS)
-	    bytes = SSL_read(ssl, destination, size);
-	else
-#else
-	    bytes = read(sockfd, destination, size);
-#endif
-	
-	if (bytes < 0) {
-	    fprintf(stderr, "%s: GET (read) failed\n", argv0);
-	    return bytes;
-	}
-	if (bytes == 0) {
-	    break;
-	}
+	bytes = read(sockfd, destination, size);
+	if (bytes == 0) break;
     }
 
-#ifdef USE_SSL
-    if (protocol == PROTO_HTTPS) {
-	SSL_free(ssl);
-	SSL_CTX_free(ssl_ctx);
-    }
-#endif
-
+    if (c) close(sockfd);
     return end - start + 1 - size;
 }
 
+
 static int httpfs_getattr(const char *path, struct stat *stbuf) {
+    off_t size;
+    int res=0;
+    time_t mtime=time(NULL);
+    
 
     memset(stbuf, 0, sizeof(struct stat));
+    
     if (strcmp(path, "/") == 0) {
-        stbuf->st_mode = S_IFDIR | 0755;	/* read, write and search by owner, read and write by all other */
+        stbuf->st_mode = S_IFDIR | 0555;
         stbuf->st_nlink = 2;
-    } else if (strcmp(path, httpfs_path) == 0) {
-        stbuf->st_mode = S_IFREG | 0555;	/* read and execute for everybody */
-        stbuf->st_nlink = 1;
-        stbuf->st_size = file_size;
+        stbuf->st_mtime = mtime;
     } else {
-	if (lstat(path+1, stbuf) == -1)
-	    return -ENOENT;
-    }
-    return 0;
-}
-
-static int httpfs_access(const char *path, int mask) {
-    int res;
-
-    if (strcmp(path, "/") == 0) {
-        return 0;
-    } else if (strcmp(path, httpfs_path) == 0) {
-	return ((mask & W_OK) == W_OK) ? -1 : 0;
-    } else {
-	res = access(path+1, mask);
-	if (res == -1)
-	    return -errno;
-    }
-    return 0;
-}
-
-static int httpfs_readlink(const char *path, char *buf, size_t size) {
-    int res;
-
-    res = readlink(path+1, buf, size - 1);
-    if (res == -1)
-        return -errno;
-
-    buf[res] = '\0';
-    return 0;
-}
+//        fprintf(fou,"getattr -------------> path: %s\n", path);
 
-static int httpfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
-                         off_t offset, struct fuse_file_info *fi) {
-    char items[300];
-    struct dirent * item;
-    off_t Pointer;
-    size_t i;
-    (void) offset;
-    (void) fi;
-   
-    if(strcmp(path, "/") != 0) {
-	DIR *dp;
-	struct dirent *de;
-	
-	dp = opendir(path + 1);
-	if (dp == NULL)
-	    return -errno;
-	
-	while ((de = readdir(dp)) != NULL) {
-	    struct stat st;
-	    memset(&st, 0, sizeof(st));
-	    st.st_ino = de->d_ino;
-	    st.st_mode = de->d_type << 12;
-	    if (filler(buf, de->d_name, &st, 0))
-		break;
+	size = getSize(path);
+	if (size < 0) {
+    	    stbuf->st_mode = S_IFDIR | 0555;
+    	    stbuf->st_nlink = 2;
+	    stbuf->st_mtime = mtime;
 	}
-
-	closedir(dp);
-	return 0;
-	
-    }
-
-    lseek(targetFd, 0, 0);
-    for (Pointer = 0; (i = getdirentries(targetFd, items, 299, &Pointer)) > 0;) {
-	for (item = (struct dirent *) items; i > 0; item = (struct dirent *) ((char *) item + item->d_reclen)) {
-            struct stat st;
-            memset(&st, 0, sizeof(st));
-            st.st_ino = item->d_ino;
-            st.st_mode = item->d_type << 12;
-	    filler(buf, item->d_name, &st, 0);
-	    i -= item->d_reclen;
+	else {
+    	    stbuf->st_mode = S_IFREG | 0444;
+    	    stbuf->st_nlink = 1;
+	    stbuf->st_size = size;
+	    stbuf->st_mtime = mtime;
 	}
-    }
-
-    filler(buf, httpfs_path + 1, NULL, 0);
-
-    return 0;
-}
-
-static int httpfs_mknod(const char *path, mode_t mode, dev_t rdev) {
-    int res;
-
-    /* On Linux this could just be 'mknod(path, mode, rdev)' but this is more portable */
-    if (S_ISREG(mode)) {
-        res = open(path+1, O_CREAT | O_EXCL | O_WRONLY, mode);
-        if (res >= 0)
-	    res = close(res);
-    } else if (S_ISFIFO(mode))
-        res = mkfifo(path, mode);
-    else
-        res = mknod(path, mode, rdev);
-    if (res == -1)
-        return -errno;
-    return 0;
-}
-
-static int httpfs_mkdir(const char *path, mode_t mode) {
-
-    if (mkdir(path+1, mode) == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int httpfs_symlink(const char *from, const char *to) {
-
-//       This function is only called, if "to" happens to reside in  mount-point-folder.
-//      "from" is always an ordinary path
+    } 
+//    else
+//	res=-ENOENT;
 	
-    if (symlink(from, to+1) == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int httpfs_unlink(const char *path) {
-    int res;
-
-    res = unlink(path+1);
-    if (res == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int httpfs_rmdir(const char *path) {
-    int res;
-
-    res = rmdir(path+1);
-    if (res == -1)
-        return -errno;
-
-    return 0;
-}
-
-static int httpfs_rename(const char *from, const char *to) {
-
-//      seems to be never called (cross-device link)
-//      replaced by copy and delete ?
-
-    if (rename(from, to+1) == -1)
-        return -errno;
-
-    return 0;
+    return res;
 }
 
-static int httpfs_link(const char *from, const char *to) {
-    int res;
-
-    res = link(from+1, to+1);
-    if (res == -1)
-        return -errno;
-
-    return 0;
+static int httpfs_access(const char *path, int mask) {
+        return 0;
 }
 
-static int httpfs_chmod(const char *path, mode_t mode) {
+static int httpfs_readdir(const char *path, void *buffer, fuse_fill_dir_t filler,
+                         off_t offset, struct fuse_file_info *fi) {
 
-    if (strcmp(path, httpfs_path) == 0) {
-	return -EACCES;
-    } else {
-	if (chmod(path+1, mode) == -1)
-            return -errno;
-    } 
-    return 0;
-}
+    char *w, *i;
+    size_t len,min_len, bytes;
+    char file[BUFSIZE];
+    char parent;
+    
 
-static int httpfs_chown(const char *path, uid_t uid, gid_t gid) {
+//if (strcmp(path,"/") !=0)
+//    return -ENOENT;
 
-    if (strcmp(path, httpfs_path) == 0) {
-	return -EACCES;
-    } else {
-	if (lchown(path+1, uid, gid) == -1)
-            return -errno;
-    }
-    return 0;
-}
+//    fprintf(fou,"-------------start-----------\n pathuri=%s\n",path);
 
-static int httpfs_truncate(const char *path, off_t size) {
+    (*filler)(buffer, ".", NULL, 0);
+    (*filler)(buffer, "..", NULL, 0);
+    
+    // download the given URL
+    w = calloc(BIGBUFSIZE, 1);
+    bytes = httpGet(path, 0, BIGBUFSIZE, w, 0);
+    if (bytes < 0) goto end;
+
+    // Now actually parse the files
+    i = w;
+    while ( (i = strcasestr(i, "href=")) != NULL ) {
+	parent=1;
+	i += 5;
+        i += strspn(i, "\t \n\r");
+
+	if (*i == '"' || *i == '\'') i++;
+	i = relative_url(i);
+
+	len = strcspn(i, "\"'\t \n\r>?");
+	while (*i == '/') {
+	    i++;
+	    len--;
+	    parent=0;
+	}
+	min_len = MIN(len, strcspn(i, "/"));
 
-    if (strcmp(path, httpfs_path) == 0) {
-	return -EACCES;
-    } else {
-	if (truncate(path+1, size) == -1)
-            return -errno;
+	if ((len > 0)&&(parent==1)) 
+	{
+    	    strncpy(file, i, min_len);
+    	    file[min_len] = '\0';
+//	    fprintf(fou,"\nfile: %s\n", file);
+//	    fprintf(fou,"http_file: %s\n", http_file);
+//	    fprintf(fou,"path: %s\n", path);
+//	    fprintf(fou,"http_path: %s\n\n", http_path);
+
+    	    if (! (strncmp(file, http_file, strlen(http_file)) == 0
+    	    && strlen(http_file)>0
+            && strncmp(path, http_path, strlen(http_path)) == 0) ) {
+	    	(*filler)(buffer, file, NULL, 0);
+	    }
+	}
     }
-    return 0;
-}
 
-static int httpfs_utime(const char *path, struct utimbuf *buf) {
+    if (strcmp(path, "/") == 0 && strlen(http_file) > 0)
+	{
+//	    (*filler)(buffer, http_file, NULL, 0);
+	}
 
-    if (strcmp(path, httpfs_path) == 0) {
-	return -EACCES;
-    } else {
-	if (utime(path+1, buf) == -1)
-            return -errno;
-    }
+    i = w;
+    end:
+    free(w);
+//    fprintf(fou,"-------------end-----------\n");
     return 0;
 }
 
 static int httpfs_open(const char *path, struct fuse_file_info *fi) {
-    int res;
+    off_t size;
 
-    if (strcmp(path, httpfs_path) == 0) {
-	if((fi->flags & 3) != O_RDONLY) {
-	    return -EACCES;
-	} else {
-	    return 0;
-	}
-    }
-    res = open(path+1, fi->flags);
-    if (res == -1)
-        return -errno;
+   if((fi->flags & 3) != O_RDONLY )
+         return -EACCES;
+         
+    size = getSize(path);
 
-    close(res);
+//    fprintf(fou,"httpfs_open ----- path: %s\n", path);
+    
+    if (size > 0) fi->fh = size-1;
     return 0;
-
 }
 
 static int httpfs_read(const char *path, char *buf, size_t size, off_t offset,
                       struct fuse_file_info *fi) {
-    int fd;
-    int res;
     size_t got;
-    (void) fi;
-    if (strcmp(path, httpfs_path) == 0) {
-	if (offset < file_size) {
-            if (offset + size > file_size)
-		size = file_size - offset;
-	    got = HttpGet(offset, size, buf);
-	    if (got < 0)
-		return -EIO;
-	    if (got != size) {
-		close(sockfd);
-		sockfd = open_client_socket(host, port);
-		got = HttpGet(offset, size, buf);
-		if (got != size)
-		    return -EIO;
-	    }
-	} else
-            got = 0;
-	return got;
-    } else {
-	fd = open(path+1, O_RDONLY);
-	if (fd == -1)
-            return -errno;
-	res = pread(fd, buf, size, offset);
-	if (res == -1)
-            res = -errno;
-	close(fd);
-	return res;
-    }
-}
 
-static int httpfs_write(const char *path, const char *buf, size_t size, 
-			off_t offset, struct fuse_file_info *fi) {
-    int fd;
-    int res;
-
-    (void) fi;
-    if (strcmp(path, httpfs_path) == 0) {
-	return -EACCES;
-    }
-    fd = open(path+1, O_WRONLY);
-    if (fd == -1)
-        return -errno;
+//    fprintf(fou,"httpfs_read ----- path: %s\n", path);
 
-    res = pwrite(fd, buf, size, offset);
-    if (res == -1)
-        res = -errno;
 
-    close(fd);
-    return res;
-}
-
-static int httpfs_statfs(const char *path, struct statvfs *stbuf) {
-    int res;
-    (void) path;
-
-    res = statvfs(".", stbuf);
-    if (res == -1)
-        return -errno;
+    got = httpGet(path, offset, size, buf, fi->fh);
+    if (got < 0)
+	return -1;
 
-    return 0;
+    return got;
 }
 
-static int httpfs_release(const char *path, struct fuse_file_info *fi) {
-	
-    /* Just a stub.  This method is optional and can safely be left unimplemented */
-    (void) path;
-    (void) fi;
-    return 0;
-}
-
-static int httpfs_fsync(const char *path, int isdatasync, struct fuse_file_info *fi) {
-
-    /* Just a stub.  This method is optional and can safely be left unimplemented */
-    (void) path;
-    (void) isdatasync;
-    (void) fi;
+static int httpfs_flush(const char *path, struct fuse_file_info *fi) {
     return 0;
 }
 
 static void *httpfs_init(void) {
-    fchdir(targetFd);	/* that's the catch */
     return NULL;
 }
 
 static void httpfs_destroy(void *arg) {
-    close(targetFd);
-}
-
-#ifdef HAVE_SETXATTR
-/* xattr operations are optional and can safely be left unimplemented */
-static int httpfs_setxattr(const char *path, const char *name, const char *value,
-                        size_t size, int flags) {
-
-    if (strcmp(path, httpfs_path) == 0)
-	return -EACCES;
-    if (lsetxattr(path+1, name, value, size, flags) == -1)
-        return -errno;
-    return 0;
-}
-
-static int httpfs_getxattr(const char *path, const char *name, char *value,
-                    size_t size) {
-    int res;
-
-    if (strcmp(path, httpfs_path) == 0)
-	return -EACCES;
-    res = lgetxattr(path+1, name, value, size);
-    if (res == -1)
-        return -errno;
-    return res;
+    return;
 }
 
-static int httpfs_listxattr(const char *path, char *list, size_t size) {
-    int res;
-
-    if (strcmp(path, httpfs_path) == 0)
-	return -EACCES;
-    res = llistxattr(path+1, list, size);
-    if (res == -1)
-        return -errno;
-    return res;
-}
-
-static int httpfs_removexattr(const char *path, const char *name) {
-
-    if (strcmp(path, httpfs_path) == 0)
-	return -EACCES;
-    if (lremovexattr(path+1, name) == -1)
-        return -errno;
-    return 0;
-}
-#endif /* HAVE_SETXATTR */
-
 static struct fuse_operations httpfs_oper = {
+    .flush	= httpfs_flush,
     .getattr	= httpfs_getattr,
     .access	= httpfs_access,
-    .readlink	= httpfs_readlink,
     .readdir	= httpfs_readdir,
-    .mknod	= httpfs_mknod,
-    .mkdir	= httpfs_mkdir,
-    .symlink	= httpfs_symlink,
-    .unlink	= httpfs_unlink,
-    .rmdir	= httpfs_rmdir,
-    .rename	= httpfs_rename,
-    .link	= httpfs_link,
-    .chmod	= httpfs_chmod,
-    .chown	= httpfs_chown,
-    .truncate	= httpfs_truncate,
-    .utime	= httpfs_utime,
     .open	= httpfs_open,
     .read	= httpfs_read,
-    .write	= httpfs_write,
-    .statfs	= httpfs_statfs,
-    .release	= httpfs_release,
-    .fsync	= httpfs_fsync,
     .init       = httpfs_init,
     .destroy    = httpfs_destroy,
-#ifdef HAVE_SETXATTR
-    .setxattr	= httpfs_setxattr,
-    .getxattr	= httpfs_getxattr,
-    .listxattr	= httpfs_listxattr,
-    .removexattr= httpfs_removexattr,
-#endif
 };
 
 int main(int argc, char *argv[]) {
     struct stat mpstat;
-    int sr;
-    char* ri;
+    int sr,ok;
     char* fusev[4];
-	
-    argv0 = argv[0];
+
+     
+
+    myself = argv[0];
     if (argc != 3) {
-	(void) fprintf(stderr, "usage:  %s url mount-point\n", argv0);
-	(void) fprintf(stderr, ">>> Version: %s <<<\n", VERSION);
+	fprintf(stderr, "HTTP Filesystem version %s\n", VERSION);
+	fprintf(stderr, "usage: %s url mount-point\n", myself);
 	return 1;
     }
-    argv1 = argv[1];
-    argv2 = argv[2];
     
-    protocol = parseURL(argv1, host, &file_name, &port);
-    if (protocol == -1) 
-	return 1;
+//    fou=fopen("out","w+");
+//    fprintf(fou,"debug:\n");
+    
+    arg_url = argv[1];
+    arg_mnt = argv[2];
 
-    sockfd = open_client_socket(host, port);
-    if (sockfd < 0)
+    ok = parse_url(arg_url);
+    if (ok == -1) 
 	return 1;
 
-    if (getSize() != 0) 
+    sockfd = open_client_socket();
+    if (sockfd < 0)
 	return 1;
 
-    sr = stat(argv2, &mpstat);
+    sr = stat(arg_mnt, &mpstat);
     if (sr < 0) {
-	(void) fprintf(stderr, "%s: bad mount-point %s\n", argv0, argv2);
+	fprintf(stderr, "%s: bad mount-point %s\n", myself, arg_mnt);
 	return 1;
     }
 
     if ((mpstat.st_mode & S_IFDIR) == 0) {
-	(void) fprintf(stderr, "%s: %s is not a directory\n", argv0, argv2);
-	return 1;
-    }
-    
-    if ((targetFd = open(argv2, 0)) == -1) {
-	(void) fprintf(stderr, "%s: open %s failed\n", argv0, argv2);
+	fprintf(stderr, "%s: %s is not a directory\n", myself, arg_mnt);
 	return 1;
     }
-    
-    ri = rindex(file_name, '/');
-    if (ri == (char *) 0) {
-	httpfs_path[0] = '/';
-	strcpy(&httpfs_path[1], file_name);
-    } else
-	strcpy(httpfs_path, ri);
-
-    fusev[0] = argv0;
-    fusev[1] = "-o";
-    fusev[2] = "nonempty";
-    fusev[3] = argv2;
+
+    fusev[0] = myself;
+    fusev[1] = "-s"; // disable multi threaded support (to make HTTP work)
+    fusev[2] = "-ononempty,attr_timeout=300,entry_timeout=300,negative_timeout=300,kernel_cache,allow_other";
+    fusev[3] = arg_mnt;
     return fuse_main(argc+1, fusev, &httpfs_oper);
     /*    close(sockfd);	*/
 }
+