Index: /trunk/ChangeLog
===================================================================
--- /trunk/ChangeLog	(revision 1139)
+++ /trunk/ChangeLog	(revision 1140)
@@ -17,4 +17,5 @@
  * closes #73: warn for improper PHP_FCGI_CHILDREN setting fcgi mode (>=PHP_5_3)
  * closes #174: updates api to support "clear all cache"
+ * closes #198: support for caching protocol url
  * fixes #39: ini_set never work for xcache.coverager setting. use API instead
  * code refactor
Index: /trunk/mod_cacher/xc_cacher.c
===================================================================
--- /trunk/mod_cacher/xc_cacher.c	(revision 1139)
+++ /trunk/mod_cacher/xc_cacher.c	(revision 1140)
@@ -243,6 +243,6 @@
 			}
 
-			assert(IS_ABSOLUTE_PATH(entry1->name.str.val, entry1->name.str.len));
-			assert(IS_ABSOLUTE_PATH(entry2->name.str.val, entry2->name.str.len));
+			assert(strstr(entry1->name.str.val, "://") != NULL || IS_ABSOLUTE_PATH(entry1->name.str.val, entry1->name.str.len));
+			assert(strstr(entry1->name.str.val, "://") != NULL || IS_ABSOLUTE_PATH(entry2->name.str.val, entry2->name.str.len));
 
 			return entry1->name.str.len == entry2->name.str.len
@@ -947,7 +947,7 @@
 /* }}} */
 
-#define XC_RESOLVE_PATH_CHECKER(name) zend_bool name(const char *filepath, size_t filepath_len, void *data TSRMLS_DC)
+#define XC_RESOLVE_PATH_CHECKER(name) int name(const char *filepath, size_t filepath_len, void *data TSRMLS_DC)
 typedef XC_RESOLVE_PATH_CHECKER((*xc_resolve_path_checker_func_t));
-static zend_bool xc_resolve_path(const char *filepath, char *path_buffer, xc_resolve_path_checker_func_t checker_func, void *data TSRMLS_DC) /* {{{ */
+static int xc_resolve_path(const char *filepath, char *path_buffer, xc_resolve_path_checker_func_t checker_func, void *data TSRMLS_DC) /* {{{ */
 {
 	char *paths, *path;
@@ -967,10 +967,5 @@
 	    !*path) {
 
-		if (checker_func(path_buffer, path_buffer_len, data TSRMLS_CC)) {
-			ret = 1;
-		}
-		else {
-			ret = FAILURE;
-		}
+		ret = checker_func(path_buffer, path_buffer_len, data TSRMLS_CC);
 		goto finish;
 	}
@@ -984,6 +979,6 @@
 		path_buffer_len = snprintf(path_buffer, MAXPATHLEN, "%s/%s", path, filepath);
 		if (path_buffer_len < MAXPATHLEN - 1) {
-			if (checker_func(path_buffer, path_buffer_len, data TSRMLS_CC)) {
-				ret = 1;
+			ret = checker_func(path_buffer, path_buffer_len, data TSRMLS_CC);
+			if (ret == SUCCESS) {
 				goto finish;
 			}
@@ -993,29 +988,22 @@
 	/* fall back to current directory */
 	if (zend_is_executing(TSRMLS_C)) {
-		const char *executed_filename = zend_get_executed_filename(TSRMLS_C);
-		if (executed_filename && executed_filename[0] && executed_filename[0] != '[') {
-			size_t filename_len = strlen(filepath);
-			size_t dirname_len;
-
-			for (dirname_len = strlen(executed_filename) - 1; dirname_len > 0; --dirname_len) {
-				if (IS_SLASH(executed_filename[dirname_len])) {
-					if (dirname_len + filename_len < MAXPATHLEN - 1) {
-						++dirname_len; /* include tailing slash */
-						memcpy(path_buffer, executed_filename, dirname_len);
-						memcpy(path_buffer + dirname_len, filepath, filename_len);
-						path_buffer_len = dirname_len + filename_len;
-						path_buffer[path_buffer_len] = '\0';
-						if (checker_func(path_buffer, path_buffer_len, data TSRMLS_CC)) {
-							ret = 1;
-							goto finish;
-						}
-					}
-					break;
-				}
-			}
-		}
-	}
-
-	ret = 0;
+		const char *executing_filename = zend_get_executed_filename(TSRMLS_C);
+		int dirname_len = strlen(executing_filename);
+		size_t filename_len = strlen(filepath);
+
+		while ((--dirname_len >= 0) && !IS_SLASH(executing_filename[dirname_len]));
+		if (executing_filename && dirname_len > 0 && executing_filename[0] && executing_filename[0] != '['
+		 && dirname_len + 1 + filename_len + 1 < MAXPATHLEN) {
+			memcpy(path_buffer, executing_filename, dirname_len + 1);
+			memcpy(path_buffer + dirname_len + 1, filepath, filename_len + 1);
+			path_buffer_len = dirname_len + 1 + filename_len;
+			ret = checker_func(path_buffer, path_buffer_len, data TSRMLS_CC);
+			if (ret == SUCCESS) {
+				goto finish;
+			}
+		}
+	}
+
+	ret = FAILURE;
 
 finish:
@@ -1025,15 +1013,51 @@
 }
 /* }}} */
+
+static zend_bool xc_is_absolute(const char *filepath, size_t filepath_len) /* {{{ */
+{
+	const char *p;
+
+	if (IS_ABSOLUTE_PATH(filepath, filepath_len)) {
+		return 1;
+	}
+
+	for (p = filepath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
+	if ((*p == ':') && (p - filepath > 1) && (p[1] == '/') && (p[2] == '/')) {
+		return 1;
+	}
+
+	return 0;
+}
+/* }}} */
+static int xc_stat(const char *filepath, struct stat *statbuf TSRMLS_DC) /* {{{ */
+{
+	if (strstr(filepath, "://") != NULL) {
+		php_stream_statbuf ssb; 
+		php_stream_wrapper *wrapper = NULL; 
+		char *path_for_open = NULL; 
+
+		wrapper = php_stream_locate_url_wrapper(filepath, &path_for_open, 0 TSRMLS_CC); 
+		if (wrapper && wrapper->wops->url_stat
+		 && wrapper != &php_plain_files_wrapper
+		 && wrapper->wops->url_stat(wrapper, path_for_open, PHP_STREAM_URL_STAT_QUIET, &ssb, NULL TSRMLS_CC) == SUCCESS) {
+			*statbuf = ssb.sb;
+			return SUCCESS;
+		}
+
+		return FAILURE;
+	}
+
+	return VCWD_STAT(filepath, statbuf);
+}
+/* }}} */
+static XC_RESOLVE_PATH_CHECKER(xc_resolve_path_stat_checker) /* {{{ */
+{
+	return xc_stat(filepath, (struct stat *) data TSRMLS_CC);
+}
+/* }}} */
 #ifndef ZEND_ENGINE_2_3
-static XC_RESOLVE_PATH_CHECKER(xc_stat_file) /* {{{ */
-{
-	return VCWD_STAT(filepath, (struct stat *) data) == 0 ? 1 : 0;
-}
-/* }}} */
 static int xc_resolve_path_stat(const char *filepath, char *path_buffer, struct stat *pbuf TSRMLS_DC) /* {{{ */
 {
-	return xc_resolve_path(filepath, path_buffer, xc_stat_file, (void *) pbuf TSRMLS_CC)
-		? SUCCESS
-		: FAILURE;
+	return xc_resolve_path(filepath, path_buffer, xc_resolve_path_stat_checker, (void *) pbuf TSRMLS_CC);
 }
 /* }}} */
@@ -1051,18 +1075,18 @@
 } xc_compiler_t;
 /* }}} */
-typedef struct xc_entry_resolve_path_data_t { /* {{{ */
+typedef struct xc_resolve_path_entry_checker_t { /* {{{ */
 	xc_compiler_t *compiler;
 	xc_entry_php_t **stored_entry;
-} xc_entry_resolve_path_data_t;
-/* }}} */
-static XC_RESOLVE_PATH_CHECKER(xc_entry_resolve_path_func_unlocked) /* {{{ */
-{
-	xc_entry_resolve_path_data_t *entry_resolve_path_data = (xc_entry_resolve_path_data_t *) data;
-	xc_compiler_t *compiler = entry_resolve_path_data->compiler;
+} xc_resolve_path_entry_checker_data_t;
+/* }}} */
+static XC_RESOLVE_PATH_CHECKER(xc_resolve_path_entry_checker) /* {{{ */
+{
+	xc_resolve_path_entry_checker_data_t *entry_checker_data = (xc_resolve_path_entry_checker_data_t *) data;
+	xc_compiler_t *compiler = entry_checker_data->compiler;
 
 	compiler->new_entry.entry.name.str.val = xc_expand_url(filepath, compiler->opened_path_buffer TSRMLS_CC);
 	compiler->new_entry.entry.name.str.len = strlen(compiler->new_entry.entry.name.str.val);
 
-	*entry_resolve_path_data->stored_entry = (xc_entry_php_t *) xc_entry_find_unlocked(
+	*entry_checker_data->stored_entry = (xc_entry_php_t *) xc_entry_find_unlocked(
 			XC_TYPE_PHP
 			, &xc_php_caches[compiler->entry_hash.cacheid]
@@ -1071,17 +1095,15 @@
 			TSRMLS_CC);
 
-	return *entry_resolve_path_data->stored_entry ? 1 : 0;
-}
-/* }}} */
-static int xc_entry_resolve_path_unlocked(xc_compiler_t *compiler, const char *filepath, xc_entry_php_t **stored_entry TSRMLS_DC) /* {{{ */
+	return *entry_checker_data->stored_entry ? SUCCESS : FAILURE;
+}
+/* }}} */
+static int xc_resolve_path_check_entry_unlocked(xc_compiler_t *compiler, const char *filepath, xc_entry_php_t **stored_entry TSRMLS_DC) /* {{{ */
 {
 	char path_buffer[MAXPATHLEN];
-	xc_entry_resolve_path_data_t entry_resolve_path_data;
-	entry_resolve_path_data.compiler = compiler;
-	entry_resolve_path_data.stored_entry = stored_entry;
-
-	return xc_resolve_path(filepath, path_buffer, xc_entry_resolve_path_func_unlocked, (void *) &entry_resolve_path_data TSRMLS_CC)
-		? SUCCESS
-		: FAILURE;
+	xc_resolve_path_entry_checker_data_t entry_checker_data;
+	entry_checker_data.compiler = compiler;
+	entry_checker_data.stored_entry = stored_entry;
+
+	return xc_resolve_path(filepath, path_buffer, xc_resolve_path_entry_checker, (void *) &entry_checker_data TSRMLS_CC);
 }
 /* }}} */
@@ -1104,6 +1126,6 @@
 
 	/* absolute path */
-	if (IS_ABSOLUTE_PATH(compiler->filename, strlen(compiler->filename))) {
-		if (statbuf && VCWD_STAT(compiler->filename, statbuf) != 0) {
+	if (xc_is_absolute(compiler->filename, strlen(compiler->filename))) {
+		if (statbuf && xc_stat(compiler->filename, statbuf TSRMLS_CC) != SUCCESS) {
 			return FAILURE;
 		}
@@ -1147,5 +1169,5 @@
 			efree(opened_path);
 			compiler->opened_path = compiler->opened_path_buffer;
-			if (!statbuf || VCWD_STAT(compiler->opened_path, statbuf) == 0) {
+			if (!statbuf || xc_stat(compiler->opened_path, statbuf TSRMLS_CC) == SUCCESS) {
 				return SUCCESS;
 			}
@@ -1169,5 +1191,5 @@
 
 		if (compiler->opened_path) {
-			if (VCWD_STAT(compiler->opened_path, &buf) != 0) {
+			if (xc_stat(compiler->opened_path, &buf TSRMLS_CC) != SUCCESS) {
 				return FAILURE;
 			}
@@ -2075,5 +2097,5 @@
 
 	ENTER_LOCK_EX(cache) {
-		if (!compiler->opened_path && xc_entry_resolve_path_unlocked(compiler, compiler->filename, &stored_entry TSRMLS_CC) == SUCCESS) {
+		if (!compiler->opened_path && xc_resolve_path_check_entry_unlocked(compiler, compiler->filename, &stored_entry TSRMLS_CC) == SUCCESS) {
 			compiler->opened_path = compiler->new_entry.entry.name.str.val;
 		}
@@ -2178,12 +2200,6 @@
 	 || !h->filename
 	 || !SG(request_info).path_translated
-	 || strstr(h->filename, "://") != NULL
-#ifdef ZEND_ENGINE_2_3
-	 /* supported by php_resolve_path */
-	 || (!XG(stat) && strstr(PG(include_path), "://") != NULL)
-#else
-	 || strstr(PG(include_path), "://") != NULL
-#endif
-	 ) {
+
+	) {
 		TRACE("%s", "cacher not enabled");
 		return old_compile_file(h, type TSRMLS_CC);
