static void aicloud_connection_smb_info_url_patch(server *srv, connection *con)
{
	char strr[2048]="\0";
	char uri[2048]="\0";
	
	UNUSED(srv);
	
	char* pch = strchr(con->request.uri->ptr,'?');
	if(pch){	
		buffer_copy_string_len(con->url_options, pch+1, strlen(pch)-1);
		int len = pch-con->request.uri->ptr;
		strncpy(uri,con->request.uri->ptr, len);
	}
	else{
		strcpy(uri,con->request.uri->ptr);
	}
	
	if(con->mode == DIRECT){
		sprintf(strr, "%s", uri);
	}
	else {
		if(con->smb_info&&con->smb_info->server->used) {
			if(con->mode == SMB_BASIC){
				if(con->smb_info->username->used&&con->smb_info->password->used){
					sprintf(strr, "smb://%s:%s@%s", con->smb_info->username->ptr, con->smb_info->password->ptr, uri+1);
				}
				else
					sprintf(strr, "smb://%s", uri+1);
			}
			else if(con->mode == SMB_NTLM){
				sprintf(strr, "smb://%s", uri+1);		
			}
		} else {
			sprintf(strr, "smb://");
		}
	}

	buffer_copy_string(con->url.path, strr);
	buffer_copy_string(con->url.rel_path, uri);	

	buffer_urldecode_path(con->url.path);
	buffer_urldecode_path(con->url.rel_path);
	
}
void http_response_xsendfile (server *srv, connection *con, buffer *path, const array *xdocroot) {
    const int status = con->http_status;
    int valid = 1;

    /* reset Content-Length, if set by backend
     * Content-Length might later be set to size of X-Sendfile static file,
     * determined by open(), fstat() to reduces race conditions if the file
     * is modified between stat() (stat_cache_get_entry()) and open(). */
    if (con->parsed_response & HTTP_CONTENT_LENGTH) {
        data_string *ds = (data_string *) array_get_element(con->response.headers, "Content-Length");
        if (ds) buffer_reset(ds->value);
        con->parsed_response &= ~HTTP_CONTENT_LENGTH;
        con->response.content_length = -1;
    }

    buffer_urldecode_path(path);
    buffer_path_simplify(path, path);
    if (con->conf.force_lowercase_filenames) {
        buffer_to_lower(path);
    }

    /* check that path is under xdocroot(s)
     * - xdocroot should have trailing slash appended at config time
     * - con->conf.force_lowercase_filenames is not a server-wide setting,
     *   and so can not be definitively applied to xdocroot at config time*/
    if (xdocroot->used) {
        size_t i, xlen = buffer_string_length(path);
        for (i = 0; i < xdocroot->used; ++i) {
            data_string *ds = (data_string *)xdocroot->data[i];
            size_t dlen = buffer_string_length(ds->value);
            if (dlen <= xlen
                    && (!con->conf.force_lowercase_filenames
                        ? 0 == memcmp(path->ptr, ds->value->ptr, dlen)
                        : 0 == strncasecmp(path->ptr, ds->value->ptr, dlen))) {
                break;
            }
        }
        if (i == xdocroot->used) {
            log_error_write(srv, __FILE__, __LINE__, "SBs",
                            "X-Sendfile (", path,
                            ") not under configured x-sendfile-docroot(s)");
            con->http_status = 403;
            valid = 0;
        }
    }

    if (valid) http_response_send_file(srv, con, path);

    if (con->http_status >= 400 && status < 300) {
        con->mode = DIRECT;
    } else if (0 != status && 200 != status) {
        con->http_status = status;
    }
}
Beispiel #3
0
handler_t http_response_prepare(server *srv, connection *con) {
	handler_t r;
Cdbg(DBE, "enter http_response_prepare..mode=[%d], status=[%d][%s]", con->mode, con->http_status, connection_get_state(con->http_status));
	/* looks like someone has already done a decision */
	if ( (con->mode == DIRECT || con->mode == SMB_BASIC || con->mode == SMB_NTLM) &&
	    (con->http_status != 0 && con->http_status != 200)) {
		/* remove a packets in the queue */
		if (con->file_finished == 0) {
			chunkqueue_reset(con->write_queue);
		}

		return HANDLER_FINISHED;
	}

	/* no decision yet, build conf->filename */
	if ( (con->mode == DIRECT || con->mode == SMB_BASIC || con->mode == SMB_NTLM) && con->physical.path->used == 0) {
		char *qstr;

		/* we only come here when we have the parse the full request again
		 *
		 * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
		 * problem here as mod_setenv might get called multiple times
		 *
		 * fastcgi-auth might lead to a COMEBACK too
		 * fastcgi again dead server too
		 *
		 * mod_compress might add headers twice too
		 *
		 *  */

		config_cond_cache_reset(srv, con);
		config_setup_connection(srv, con); /* Perhaps this could be removed at other places. */
		
		if (con->conf.log_condition_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "run condition");
		}

		config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
		
		/**
		 * prepare strings
		 *
		 * - uri.path_raw
		 * - uri.path (secure)
		 * - uri.query
		 *
		 */

		/**
		 * Name according to RFC 2396
		 *
		 * - scheme
		 * - authority
		 * - path
		 * - query
		 *
		 * (scheme)://(authority)(path)?(query)#fragment
		 *
		 *
		 */

		if (con->conf.is_ssl) {
			buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("https"));
		} else {
			buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http"));
		}
		buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
		buffer_to_lower(con->uri.authority);
		
		config_patch_connection(srv, con, COMP_HTTP_SCHEME);    /* Scheme:      */
		config_patch_connection(srv, con, COMP_HTTP_HOST);      /* Host:        */
		config_patch_connection(srv, con, COMP_HTTP_REMOTE_IP); /* Client-IP */
		config_patch_connection(srv, con, COMP_HTTP_REFERER);   /* Referer:     */
		config_patch_connection(srv, con, COMP_HTTP_USER_AGENT);/* User-Agent:  */
		config_patch_connection(srv, con, COMP_HTTP_LANGUAGE);  /* Accept-Language:  */
		config_patch_connection(srv, con, COMP_HTTP_COOKIE);    /* Cookie:  */
		config_patch_connection(srv, con, COMP_HTTP_REQUEST_METHOD); /* REQUEST_METHOD */

		/** their might be a fragment which has to be cut away */
		if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) {
			con->request.uri->used = qstr - con->request.uri->ptr;
			con->request.uri->ptr[con->request.uri->used++] = '\0';
		}

		/** extract query string from request.uri */
		if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
			buffer_copy_string(con->uri.query, qstr + 1);
			buffer_copy_string_len(con->uri.path_raw, con->request.uri->ptr, qstr - con->request.uri->ptr);
		} else {
			buffer_reset(con->uri.query);
			buffer_copy_string_buffer(con->uri.path_raw, con->request.uri);
		}

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- splitting Request-URI");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Request-URI  : ", con->request.uri);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-scheme   : ", con->uri.scheme);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-authority: ", con->uri.authority);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path     : ", con->uri.path_raw);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-query    : ", con->uri.query);
		}


		/**
		 *
		 * call plugins
		 *
		 * - based on the raw URL
		 *
		 */		
		switch(r = plugins_call_handle_uri_raw(srv, con)) {
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
			return r;
		default:
			log_error_write(srv, __FILE__, __LINE__, "sd", "handle_uri_raw: unknown return value", r);
			break;
		}

		/* build filename
		 *
		 * - decode url-encodings  (e.g. %20 -> ' ')
		 * - remove path-modifiers (e.g. /../)
		 */
		if (con->request.http_method == HTTP_METHOD_OPTIONS &&
		    con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
			/* OPTIONS * ... */
			buffer_copy_string_buffer(con->uri.path, con->uri.path_raw);
		} else {
			buffer_copy_string_buffer(srv->tmp_buf, con->uri.path_raw);
			buffer_urldecode_path(srv->tmp_buf);			
			buffer_path_simplify(con->uri.path, srv->tmp_buf);			
		}

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- sanatising URI");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path     : ", con->uri.path);
		}

#ifdef USE_OPENSSL
		if (con->conf.is_ssl && con->conf.ssl_verifyclient) {
			https_add_ssl_entries(con);
		}
#endif

		/**
		 *
		 * call plugins
		 *
		 * - based on the clean URL
		 *
		 */
		config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
		config_patch_connection(srv, con, COMP_HTTP_QUERY_STRING); /* HTTPqs */

		/* do we have to downgrade to 1.0 ? */
		if (!con->conf.allow_http11) {
			con->request.http_version = HTTP_VERSION_1_0;
		}
		
		switch(r = plugins_call_handle_uri_clean(srv, con)) {
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
			return r;
		default:
			log_error_write(srv, __FILE__, __LINE__, "");
			break;
		}
		
		if (con->request.http_method == HTTP_METHOD_OPTIONS &&
		    con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
			/* option requests are handled directly without checking of the path */

			response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));

			con->http_status = 200;
			con->file_finished = 1;

			return HANDLER_FINISHED;
		}

		/***
		 *
		 * border
		 *
		 * logical filename (URI) becomes a physical filename here
		 *
		 *
		 *
		 */




		/* 1. stat()
		 * ... ISREG() -> ok, go on
		 * ... ISDIR() -> index-file -> redirect
		 *
		 * 2. pathinfo()
		 * ... ISREG()
		 *
		 * 3. -> 404
		 *
		 */

		/*
		 * SEARCH DOCUMENT ROOT
		 */

		/* set a default */
		buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
		buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
		
#if defined(__WIN32) || defined(__CYGWIN__)
		/* strip dots from the end and spaces
		 *
		 * windows/dos handle those filenames as the same file
		 *
		 * foo == foo. == foo..... == "foo...   " == "foo..  ./"
		 *
		 * This will affect in some cases PATHINFO
		 *
		 * on native windows we could prepend the filename with \\?\ to circumvent
		 * this behaviour. I have no idea how to push this through cygwin
		 *
		 * */

		if (con->physical.rel_path->used > 1) {
			buffer *b = con->physical.rel_path;
			size_t i;

			if (b->used > 2 &&
			    b->ptr[b->used-2] == '/' &&
			    (b->ptr[b->used-3] == ' ' ||
			     b->ptr[b->used-3] == '.')) {
				b->ptr[b->used--] = '\0';
			}

			for (i = b->used - 2; b->used > 1; i--) {
				if (b->ptr[i] == ' ' ||
				    b->ptr[i] == '.') {
					b->ptr[b->used--] = '\0';
				} else {
					break;
				}
			}
		}
#endif

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- before doc_root");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}
		/* the docroot plugin should set the doc_root and might also set the physical.path
		 * for us (all vhost-plugins are supposed to set the doc_root)
		 * */
		switch(r = plugins_call_handle_docroot(srv, con)) {
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
			return r;
		default:
			log_error_write(srv, __FILE__, __LINE__, "");
			break;
		}
		
		/* MacOS X and Windows can't distiguish between upper and lower-case
		 *
		 * convert to lower-case
		 */
		if (con->conf.force_lowercase_filenames) {
			buffer_to_lower(con->physical.rel_path);
		}
		
		/* the docroot plugins might set the servername, if they don't we take http-host */
		if (buffer_is_empty(con->server_name)) {
			buffer_copy_string_buffer(con->server_name, con->uri.authority);
		}
		
		/**
		 * create physical filename
		 * -> physical.path = docroot + rel_path
		 *
		 */		
		buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
		BUFFER_APPEND_SLASH(con->physical.path);
		buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
		if (con->physical.rel_path->used &&
		    con->physical.rel_path->ptr[0] == '/') {
		    
			buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
			
			//buffer_append_string_encoded(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2, ENCODING_REL_URI);
			//Cdbg(1,"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa %s", con->physical.path->ptr);
		} else {		
			buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
		}
		
		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after doc_root");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}
		
		switch(r = plugins_call_handle_physical(srv, con)) {
			case HANDLER_GO_ON:
				break;
			case HANDLER_FINISHED:
			case HANDLER_COMEBACK:
			case HANDLER_WAIT_FOR_EVENT:
			case HANDLER_ERROR:
				return r;
			default:
				log_error_write(srv, __FILE__, __LINE__, "");
				break;
		}
		
		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- logical -> physical");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}
	}
	
	/*
	 * Noone catched away the file from normal path of execution yet (like mod_access)
	 *
	 * Go on and check of the file exists at all
	 */
	if (con->mode == DIRECT || con->mode == SMB_BASIC || con->mode == SMB_NTLM) {
		char *slash = NULL;
		char *pathinfo = NULL;
		int found = 0;
		stat_cache_entry *sce = NULL;
		
		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling physical path");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}
		
		if ( HANDLER_ERROR != stat_cache_get_entry(srv, con, smbc_wrapper_physical_url_path(srv, con), &sce)) {
			/* file exists */

			if (con->conf.log_request_handling) {
				log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file found");
				log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
			}
#ifdef HAVE_LSTAT
			if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
				con->http_status = 403;

				if (con->conf.log_request_handling) {
					log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
					log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				}
				
				buffer_reset(con->physical.path);
				return HANDLER_FINISHED;
			};
#endif
			if (S_ISDIR(sce->st.st_mode)) {
				if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
					/* redirect to .../ */

					http_response_redirect_to_directory(srv, con);

					return HANDLER_FINISHED;
				}
#ifdef HAVE_LSTAT
			} else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) {
#else
			} else if (!S_ISREG(sce->st.st_mode)) {
#endif
				/* any special handling of non-reg files ?*/


			}
		} 
		else {		
			switch (errno) {
			case EACCES:
				con->http_status = 403;

				if (con->conf.log_request_handling) {
					log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied");
					log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				}
				
				buffer_reset(con->physical.path);
				return HANDLER_FINISHED;
			case ENOENT:
				con->http_status = 404;
				
				if (con->conf.log_request_handling) {
					log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file not found");
					log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				}

				buffer_reset(con->physical.path);
				return HANDLER_FINISHED;
			case ENOTDIR:
				/* PATH_INFO ! :) */
				break;
			default:
				/* we have no idea what happend. let's tell the user so. */
				con->http_status = 500;
				buffer_reset(con->physical.path);
				
				log_error_write(srv, __FILE__, __LINE__, "ssbsb",
						"file not found ... or so: ", strerror(errno),
						con->uri.path,
						"->", con->physical.path);

				return HANDLER_FINISHED;
			}

			/* not found, perhaps PATHINFO */

			buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
			
			do {
				if (slash) {
					buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
				} else {
					buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
				}

				if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {				
					found = S_ISREG(sce->st.st_mode);
					break;
				}

				if (pathinfo != NULL) {
					*pathinfo = '\0';
				}
				slash = strrchr(srv->tmp_buf->ptr, '/');

				if (pathinfo != NULL) {
					/* restore '/' */
					*pathinfo = '/';
				}

				if (slash) pathinfo = slash;
			} while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (con->physical.basedir->used - 2)));

			if (found == 0) {
				/* no it really doesn't exists */
				con->http_status = 404;

				if (con->conf.log_file_not_found) {
					log_error_write(srv, __FILE__, __LINE__, "sbsb",
							"file not found:", con->uri.path,
							"->", con->physical.path);
				}

				buffer_reset(con->physical.path);

				return HANDLER_FINISHED;
			}

#ifdef HAVE_LSTAT
			if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
				con->http_status = 403;

				if (con->conf.log_request_handling) {
					log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
					log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				}

				buffer_reset(con->physical.path);
				return HANDLER_FINISHED;
			};
#endif

			/* we have a PATHINFO */
			if (pathinfo) {
				buffer_copy_string(con->request.pathinfo, pathinfo);

				/*
				 * shorten uri.path
				 */

				con->uri.path->used -= strlen(pathinfo);
				con->uri.path->ptr[con->uri.path->used - 1] = '\0';
			}

			if (con->conf.log_request_handling) {
				log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after pathinfo check");
				log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
				log_error_write(srv, __FILE__, __LINE__,  "sb", "Pathinfo     :", con->request.pathinfo);
			}
		}

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling subrequest");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}
		
		/* call the handlers */
		switch(r = plugins_call_handle_subrequest_start(srv, con)) {
		case HANDLER_GO_ON:
			/* request was not handled */
			break;
		case HANDLER_FINISHED:
		default:
			if (con->conf.log_request_handling) {
				log_error_write(srv, __FILE__, __LINE__,  "s",  "-- subrequest finished");
			}

			/* something strange happend */
			return r;
		}

		/* if we are still here, no one wanted the file, status 403 is ok I think */

		if ((con->mode == DIRECT || con->mode == SMB_BASIC || con->mode == SMB_NTLM) && con->http_status == 0) {
			switch (con->request.http_method) {
			case HTTP_METHOD_OPTIONS:
				con->http_status = 200;
				break;
			default:
				con->http_status = 403;
			}

			return HANDLER_FINISHED;
		}

	}

	switch(r = plugins_call_handle_subrequest(srv, con)) {
	case HANDLER_GO_ON:
		/* request was not handled, looks like we are done */
		return HANDLER_FINISHED;
	case HANDLER_FINISHED:
		/* request is finished */
	default:
		/* something strange happend */
		return r;
	}

	/* can't happen */
	return HANDLER_COMEBACK;
}
Beispiel #4
0
handler_t http_prepare_response(server *srv, connection *con)
{
	if (NULL == srv || NULL == con)
	{
		return HANDLER_ERROR;
	}
	
	if (con -> http_status >=400 && con -> http_status <600)
	{
		//有错误直接返回。
		//说明已经处理过了。不需要在处理。
		return HANDLER_FINISHED;
	}
	
	handler_t ht;
	/*
	 * 分析uri地址。  /pages/index.html?key1=data&key2=data2#frangement
	 * 将解析好的uri地址存放在con -> uri中。
	 * 其中fangement直接乎略。
	 */
	buffer *uri = con -> request.uri;
	if (uri -> ptr[0] != '/')
	{
		log_error_write(srv, __FILE__, __LINE__, "sb", "bad uri. not begin with /.", uri);
		return HANDLER_ERROR;
	}
	//log_error_write(srv, __FILE__, __LINE__, "sb", "Request.uri", uri);
	
	char *query;
	if (NULL == (query = strchr(uri -> ptr, '?')))
	{
		//没有query部分。只有uri地址。
		buffer_copy_string(con -> uri.path_raw, uri -> ptr);
	}
	else
	{
		//有query数据。
		char *frag;
		if (NULL != (frag =strchr(uri -> ptr, '#')))
		{
			//有frangement数据。直接乎略。
			*frag = '\0';
		}
		
		*query = '\0';
		++query;
		buffer_copy_string(con -> uri.query, query);
		buffer_copy_string(con -> uri.path_raw, uri -> ptr);
	}
	
	//log_error_write(srv, __FILE__, __LINE__, "sb", "path_raw:", con -> uri.path_raw);
	//log_error_write(srv, __FILE__, __LINE__, "sb", "query:", con -> uri.query);
	
	buffer_copy_string_len(con -> uri.scheme, CONST_STR_LEN("http"));
	if (con->request.http_method == HTTP_METHOD_OPTIONS &&
			con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0')
	{
		buffer_copy_string_len(con -> uri.path_raw, CONST_STR_LEN("*"));
		buffer_copy_string_len(con -> uri.path, CONST_STR_LEN("*"));
		http_response_insert_header(srv, con, CONST_STR_LEN("Allow")
											, CONST_STR_LEN("GET, POST, OPTIONS, HEAD"));
		con -> http_status = 200;
		return HANDLER_FINISHED;
	}
	else
	{
		//简化地址。
		buffer_reset(con -> tmp_buf);
		buffer_path_simplify(con -> tmp_buf, con -> uri.path_raw);
		buffer_copy_string_buffer(con -> uri.path_raw, con -> tmp_buf);
	}
	//log_error_write(srv, __FILE__, __LINE__, "sb", "Simple path:", con -> uri.path_raw);
	
	/*
	 * 得到没有解码的url地址。调用插件。
	 */
	switch(ht = plugin_handle_url_raw(srv, con))
	{
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
		case HANDLER_WAIT_FOR_FD:
			return ht;
		default:
			log_error_write(srv, __FILE__, __LINE__, "s", "Unknown handler state.");
			break;
	}
	
	//解码url地址和query数据。
	buffer_reset(con -> tmp_buf);
	buffer_copy_string_buffer(con -> tmp_buf, con -> uri.path_raw);
	buffer_urldecode_path(con -> tmp_buf);
	buffer_copy_string_buffer(con -> uri.path, con -> tmp_buf);
	//log_error_write(srv, __FILE__, __LINE__, "sb", "decode path:", con -> uri.path);
	
	buffer_urldecode_query(con -> uri.query);
	//log_error_write(srv, __FILE__, __LINE__, "sb", "decode query:", con -> uri.query);
	
	/*
	 * 解码url地址。调用插件。
	 */
	switch(ht = plugin_handle_url_clean(srv, con))
	{
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
		case HANDLER_WAIT_FOR_FD:
			return ht;
		default:
			log_error_write(srv, __FILE__, __LINE__, "s", "Unknown handler state.");
			break;
	}
	
	/*
	 * OPTIONS方法直接返回允许。
	 */
	if (con->request.http_method == HTTP_METHOD_OPTIONS &&
			con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0')
	{
		/*
		 * path  将key=val加到response的head中。
		 */
		http_response_insert_header(srv, con, CONST_STR_LEN("Allow"),
						   CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
		con->http_status = 200;
		//con->file_finished = 1;
		return HANDLER_FINISHED;
	}
		
	//设置连接处理时的默认根目录。
	//在调用docroot插件功能时,将根据需要重写这个根目录。
	buffer_copy_string_buffer(con -> physical.doc_root, srv -> srvconf.docroot);
	
	/*
	 * 有些插件需要设置工作根目录。
	 */
	switch(ht = plugin_handle_docroot(srv, con))
	{
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
		case HANDLER_WAIT_FOR_FD:
			return ht;
		default:
			log_error_write(srv, __FILE__, __LINE__, "s", "Unknown handler state.");
			break;
	}

	//拼接物理地址。
	buffer_reset(con -> tmp_buf);
	buffer_copy_string_buffer(con -> tmp_buf, con -> physical.doc_root);
	buffer_append_string_buffer(con -> tmp_buf, con -> uri.path);
	buffer_copy_string_buffer(con -> physical.path, con -> uri.path);
	buffer_path_simplify(con -> physical.real_path, con -> tmp_buf);
	
	//log_error_write(srv, __FILE__, __LINE__, "sb", "pyhsical path:", con -> physical.real_path);
	/*
	 * 得到物理地址。 调用插件。
	 */
	switch(ht = plugin_handle_physical(srv, con))
	{
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
		case HANDLER_WAIT_FOR_FD:
			return ht;
		default:
			log_error_write(srv, __FILE__, __LINE__, "s", "Unknown handler state.");
			break;
	}

	//检查所请求的资源是否存在。
	if (-1 == response_physical_exist(srv, con, con -> physical.real_path))
	{
		return HANDLER_FINISHED;
	}
	//如果请求的是目录,直接提示用户跳转。
	if(con -> http_status != 0)
	{
		return HANDLER_FINISHED;
	}
	//资源存在,继续处理请求。
	
	/*
	 * 子请求开始。
	 * 通常,插件的主要处理工作在下面三个函数调用中。。
	 */
	switch(ht = plugin_handle_subrequest_start(srv, con))
	{
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
		case HANDLER_WAIT_FOR_FD:
			return ht;
		default:
			log_error_write(srv, __FILE__, __LINE__, "s", "Unknown handler state.");
			break;
	}

	/*
	 * 处理子请求。
	 * 通常是真正的对请求进行处理。
	 */
	switch(ht = plugin_handle_handle_subrequest(srv, con))
	{
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
		case HANDLER_WAIT_FOR_FD:
			return ht;
		default:
			log_error_write(srv, __FILE__, __LINE__, "s", "Unknown handler state.");
			break;
	}

	/*
	 * 子请求处理结束。
	 * 做一些清理标记工作。
	 */
	switch(ht = plugin_handle_subrequest_end(srv, con))
	{
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
		case HANDLER_WAIT_FOR_FD:
			return ht;
		default:
			log_error_write(srv, __FILE__, __LINE__, "s", "Unknown handler state.");
			break;
	}
	
	//处理静态页面。
	switch(ht = response_handle_static_file(srv, con))
	{
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
		case HANDLER_WAIT_FOR_FD:
			return ht;
		default:
			log_error_write(srv, __FILE__, __LINE__, "s", "Unknown handler state.");
			break;
	}
	
	/*
	 * 到这就出错了。。。
	 */
	return HANDLER_ERROR;
}
Beispiel #5
0
static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const char **l, size_t n, stat_cache_entry *sce) {
	size_t i, ssicmd = 0;
	char buf[255];
	buffer *b = NULL;

	struct {
		const char *var;
		enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
				SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
				SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
	} ssicmds[] = {
		{ "echo",     SSI_ECHO },
		{ "include",  SSI_INCLUDE },
		{ "flastmod", SSI_FLASTMOD },
		{ "fsize",    SSI_FSIZE },
		{ "config",   SSI_CONFIG },
		{ "printenv", SSI_PRINTENV },
		{ "set",      SSI_SET },
		{ "if",       SSI_IF },
		{ "elif",     SSI_ELIF },
		{ "endif",    SSI_ENDIF },
		{ "else",     SSI_ELSE },
		{ "exec",     SSI_EXEC },

		{ NULL, SSI_UNSET }
	};

	for (i = 0; ssicmds[i].var; i++) {
		if (0 == strcmp(l[1], ssicmds[i].var)) {
			ssicmd = ssicmds[i].type;
			break;
		}
	}

	switch(ssicmd) {
	case SSI_ECHO: {
		/* echo */
		int var = 0;
		/* int enc = 0; */
		const char *var_val = NULL;

		struct {
			const char *var;
			enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
					SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
		} echovars[] = {
			{ "DATE_GMT",      SSI_ECHO_DATE_GMT },
			{ "DATE_LOCAL",    SSI_ECHO_DATE_LOCAL },
			{ "DOCUMENT_NAME", SSI_ECHO_DOCUMENT_NAME },
			{ "DOCUMENT_URI",  SSI_ECHO_DOCUMENT_URI },
			{ "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
			{ "USER_NAME",     SSI_ECHO_USER_NAME },

			{ NULL, SSI_ECHO_UNSET }
		};

/*
		struct {
			const char *var;
			enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
		} encvars[] = {
			{ "url",          SSI_ENC_URL },
			{ "none",         SSI_ENC_NONE },
			{ "entity",       SSI_ENC_ENTITY },

			{ NULL, SSI_ENC_UNSET }
		};
*/

		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "var")) {
				int j;

				var_val = l[i+1];

				for (j = 0; echovars[j].var; j++) {
					if (0 == strcmp(l[i+1], echovars[j].var)) {
						var = echovars[j].type;
						break;
					}
				}
			} else if (0 == strcmp(l[i], "encoding")) {
/*
				int j;

				for (j = 0; encvars[j].var; j++) {
					if (0 == strcmp(l[i+1], encvars[j].var)) {
						enc = encvars[j].type;
						break;
					}
				}
*/
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}

		if (p->if_is_false) break;

		if (!var_val) {
			log_error_write(srv, __FILE__, __LINE__, "sss",
					"ssi: ",
					l[1], "var is missing");
			break;
		}

		switch(var) {
		case SSI_ECHO_USER_NAME: {
			struct passwd *pw;

			b = chunkqueue_get_append_buffer(con->write_queue);
#ifdef HAVE_PWD_H
			if (NULL == (pw = getpwuid(sce->st.st_uid))) {
				buffer_copy_long(b, sce->st.st_uid);
			} else {
				buffer_copy_string(b, pw->pw_name);
			}
#else
			buffer_copy_long(b, sce->st.st_uid);
#endif
			break;
		}
		case SSI_ECHO_LAST_MODIFIED:	{
			time_t t = sce->st.st_mtime;

			b = chunkqueue_get_append_buffer(con->write_queue);
			if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
				buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
			} else {
				buffer_copy_string(b, buf);
			}
			break;
		}
		case SSI_ECHO_DATE_LOCAL: {
			time_t t = time(NULL);

			b = chunkqueue_get_append_buffer(con->write_queue);
			if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
				buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
			} else {
				buffer_copy_string(b, buf);
			}
			break;
		}
		case SSI_ECHO_DATE_GMT: {
			time_t t = time(NULL);

			b = chunkqueue_get_append_buffer(con->write_queue);
			if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
				buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
			} else {
				buffer_copy_string(b, buf);
			}
			break;
		}
		case SSI_ECHO_DOCUMENT_NAME: {
			char *sl;

			b = chunkqueue_get_append_buffer(con->write_queue);
			if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
				buffer_copy_string_buffer(b, con->physical.path);
			} else {
				buffer_copy_string(b, sl + 1);
			}
			break;
		}
		case SSI_ECHO_DOCUMENT_URI: {
			b = chunkqueue_get_append_buffer(con->write_queue);
			buffer_copy_string_buffer(b, con->uri.path);
			break;
		}
		default: {
			data_string *ds;
			/* check if it is a cgi-var */

			b = chunkqueue_get_append_buffer(con->write_queue);

			if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
				buffer_copy_string_buffer(b, ds->value);
			} else {
				buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
			}

			break;
		}
		}
		break;
	}
	case SSI_INCLUDE:
	case SSI_FLASTMOD:
	case SSI_FSIZE: {
		const char * file_path = NULL, *virt_path = NULL;
		struct stat st;
		char *sl;

		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "file")) {
				file_path = l[i+1];
			} else if (0 == strcmp(l[i], "virtual")) {
				virt_path = l[i+1];
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}

		if (!file_path && !virt_path) {
			log_error_write(srv, __FILE__, __LINE__, "sss",
					"ssi: ",
					l[1], "file or virtual are missing");
			break;
		}

		if (file_path && virt_path) {
			log_error_write(srv, __FILE__, __LINE__, "sss",
					"ssi: ",
					l[1], "only one of file and virtual is allowed here");
			break;
		}


		if (p->if_is_false) break;

		if (file_path) {
			/* current doc-root */
			if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
				buffer_copy_string_len(p->stat_fn, CONST_STR_LEN("/"));
			} else {
				buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
			}

			buffer_copy_string(srv->tmp_buf, file_path);
			buffer_urldecode_path(srv->tmp_buf);
			buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
			buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
		} else {
			/* virtual */

			if (virt_path[0] == '/') {
				buffer_copy_string(p->stat_fn, virt_path);
			} else {
				/* there is always a / */
				sl = strrchr(con->uri.path->ptr, '/');

				buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
				buffer_append_string(p->stat_fn, virt_path);
			}

			buffer_urldecode_path(p->stat_fn);
			buffer_path_simplify(srv->tmp_buf, p->stat_fn);

			/* we have an uri */

			buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
			buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
		}

		if (0 == stat(p->stat_fn->ptr, &st)) {
			time_t t = st.st_mtime;

			switch (ssicmd) {
			case SSI_FSIZE:
				b = chunkqueue_get_append_buffer(con->write_queue);
				if (p->sizefmt) {
					int j = 0;
					const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };

					off_t s = st.st_size;

					for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);

					buffer_copy_off_t(b, s);
					buffer_append_string(b, abr[j]);
				} else {
					buffer_copy_off_t(b, st.st_size);
				}
				break;
			case SSI_FLASTMOD:
				b = chunkqueue_get_append_buffer(con->write_queue);
				if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
					buffer_copy_string_len(b, CONST_STR_LEN("(none)"));
				} else {
					buffer_copy_string(b, buf);
				}
				break;
			case SSI_INCLUDE:
				chunkqueue_append_file(con->write_queue, p->stat_fn, 0, st.st_size);

				/* Keep the newest mtime of included files */
				if (st.st_mtime > include_file_last_mtime)
				  include_file_last_mtime = st.st_mtime;

				break;
			}
		} else {
			log_error_write(srv, __FILE__, __LINE__, "sbs",
					"ssi: stating failed ",
					p->stat_fn, strerror(errno));
		}
		break;
	}
	case SSI_SET: {
		const char *key = NULL, *val = NULL;
		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "var")) {
				key = l[i+1];
			} else if (0 == strcmp(l[i], "value")) {
				val = l[i+1];
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}

		if (p->if_is_false) break;

		if (key && val) {
			data_string *ds;

			if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
				ds = data_string_init();
			}
			buffer_copy_string(ds->key,   key);
			buffer_copy_string(ds->value, val);

			array_insert_unique(p->ssi_vars, (data_unset *)ds);
		} else {
			log_error_write(srv, __FILE__, __LINE__, "sss",
					"ssi: var and value have to be set in",
					l[0], l[1]);
		}
		break;
	}
	case SSI_CONFIG:
		if (p->if_is_false) break;

		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "timefmt")) {
				buffer_copy_string(p->timefmt, l[i+1]);
			} else if (0 == strcmp(l[i], "sizefmt")) {
				if (0 == strcmp(l[i+1], "abbrev")) {
					p->sizefmt = 1;
				} else if (0 == strcmp(l[i+1], "abbrev")) {
					p->sizefmt = 0;
				} else {
					log_error_write(srv, __FILE__, __LINE__, "sssss",
							"ssi: unknow value for attribute '",
							l[i],
							"' for ",
							l[1], l[i+1]);
				}
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}
		break;
	case SSI_PRINTENV:
		if (p->if_is_false) break;

		b = chunkqueue_get_append_buffer(con->write_queue);
		for (i = 0; i < p->ssi_vars->used; i++) {
			data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];

			buffer_append_string_buffer(b, ds->key);
			buffer_append_string_len(b, CONST_STR_LEN("="));
			buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
			buffer_append_string_len(b, CONST_STR_LEN("\n"));
		}
		for (i = 0; i < p->ssi_cgi_env->used; i++) {
			data_string *ds = (data_string *)p->ssi_cgi_env->data[p->ssi_cgi_env->sorted[i]];

			buffer_append_string_buffer(b, ds->key);
			buffer_append_string_len(b, CONST_STR_LEN("="));
			buffer_append_string_encoded(b, CONST_BUF_LEN(ds->value), ENCODING_MINIMAL_XML);
			buffer_append_string_len(b, CONST_STR_LEN("\n"));
		}

		break;
	case SSI_EXEC: {
		const char *cmd = NULL;
		pid_t pid;
		int from_exec_fds[2];

		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "cmd")) {
				cmd = l[i+1];
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}

		if (p->if_is_false) break;

		/* create a return pipe and send output to the html-page
		 *
		 * as exec is assumed evil it is implemented synchronously
		 */

		if (!cmd) break;
#ifdef HAVE_FORK
		if (pipe(from_exec_fds)) {
			log_error_write(srv, __FILE__, __LINE__, "ss",
					"pipe failed: ", strerror(errno));
			return -1;
		}

		/* fork, execve */
		switch (pid = fork()) {
		case 0: {
			/* move stdout to from_rrdtool_fd[1] */
			close(STDOUT_FILENO);
			dup2(from_exec_fds[1], STDOUT_FILENO);
			close(from_exec_fds[1]);
			/* not needed */
			close(from_exec_fds[0]);

			/* close stdin */
			close(STDIN_FILENO);

			execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);

			log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);

			/* */
			SEGFAULT();
			break;
		}
		case -1:
			/* error */
			log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
			break;
		default: {
			/* father */
			int status;
			ssize_t r;
			int was_interrupted = 0;

			close(from_exec_fds[1]);

			/* wait for the client to end */

			/*
			 * OpenBSD and Solaris send a EINTR on SIGCHILD even if we ignore it
			 */
			do {
				if (-1 == waitpid(pid, &status, 0)) {
					if (errno == EINTR) {
						was_interrupted++;
					} else {
						was_interrupted = 0;
						log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
					}
				} else if (WIFEXITED(status)) {
					int toread;
					/* read everything from client and paste it into the output */
					was_interrupted = 0;
	
					while(1) {
						if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
							log_error_write(srv, __FILE__, __LINE__, "s",
								"unexpected end-of-file (perhaps the ssi-exec process died)");
							return -1;
						}
	
						if (toread > 0) {
							b = chunkqueue_get_append_buffer(con->write_queue);
	
							buffer_prepare_copy(b, toread + 1);
	
							if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
								/* read failed */
								break;
							} else {
								b->used = r;
								b->ptr[b->used++] = '\0';
							}
						} else {
							break;
						}
					}
				} else {
					was_interrupted = 0;
					log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
				}
			} while (was_interrupted > 0 && was_interrupted < 4); /* if waitpid() gets interrupted, retry, but max 4 times */

			close(from_exec_fds[0]);

			break;
		}
		}
#else

		return -1;
#endif

		break;
	}
	case SSI_IF: {
		const char *expr = NULL;

		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "expr")) {
				expr = l[i+1];
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}

		if (!expr) {
			log_error_write(srv, __FILE__, __LINE__, "sss",
					"ssi: ",
					l[1], "expr missing");
			break;
		}

		if ((!p->if_is_false) &&
		    ((p->if_is_false_level == 0) ||
		     (p->if_level < p->if_is_false_level))) {
			switch (ssi_eval_expr(srv, con, p, expr)) {
			case -1:
			case 0:
				p->if_is_false = 1;
				p->if_is_false_level = p->if_level;
				break;
			case 1:
				p->if_is_false = 0;
				break;
			}
		}

		p->if_level++;

		break;
	}
	case SSI_ELSE:
		p->if_level--;

		if (p->if_is_false) {
			if ((p->if_level == p->if_is_false_level) &&
			    (p->if_is_false_endif == 0)) {
				p->if_is_false = 0;
			}
		} else {
			p->if_is_false = 1;

			p->if_is_false_level = p->if_level;
		}
		p->if_level++;

		break;
	case SSI_ELIF: {
		const char *expr = NULL;
		for (i = 2; i < n; i += 2) {
			if (0 == strcmp(l[i], "expr")) {
				expr = l[i+1];
			} else {
				log_error_write(srv, __FILE__, __LINE__, "sss",
						"ssi: unknow attribute for ",
						l[1], l[i]);
			}
		}

		if (!expr) {
			log_error_write(srv, __FILE__, __LINE__, "sss",
					"ssi: ",
					l[1], "expr missing");
			break;
		}

		p->if_level--;

		if (p->if_level == p->if_is_false_level) {
			if ((p->if_is_false) &&
			    (p->if_is_false_endif == 0)) {
				switch (ssi_eval_expr(srv, con, p, expr)) {
				case -1:
				case 0:
					p->if_is_false = 1;
					p->if_is_false_level = p->if_level;
					break;
				case 1:
					p->if_is_false = 0;
					break;
				}
			} else {
				p->if_is_false = 1;
				p->if_is_false_level = p->if_level;
				p->if_is_false_endif = 1;
			}
		}

		p->if_level++;

		break;
	}
	case SSI_ENDIF:
		p->if_level--;

		if (p->if_level == p->if_is_false_level) {
			p->if_is_false = 0;
			p->if_is_false_endif = 0;
		}

		break;
	default:
		log_error_write(srv, __FILE__, __LINE__, "ss",
				"ssi: unknow ssi-command:",
				l[1]);
		break;
	}

	return 0;

}
output_file_list(server *srv, connection *con, char* fullpath, char* filename, buffer *out) {

	buffer* buffer_filename = buffer_init();
	buffer_copy_string(buffer_filename,filename);
	buffer_urldecode_path(buffer_filename);
	
	buffer_append_string_len(out, CONST_STR_LEN("<div class='albumDiv' title=''>\n"));
	buffer_append_string_len(out, CONST_STR_LEN("<table class='thumb-table-parent'>\n"));
	buffer_append_string_len(out, CONST_STR_LEN("<tbody><tr><td>\n"));
	buffer_append_string_len(out, CONST_STR_LEN("<div class='picDiv'>"));

	int use_http_connect = 0;
	
	char* aa = get_filename_ext(fullpath);
	int len = strlen(aa)+1; 		
	char* file_ext = (char*)malloc(len);
	memset(file_ext,'\0', len);
	strcpy(file_ext, aa);
	for (int i = 0; file_ext[i]; i++)
		file_ext[i] = tolower(file_ext[i]);
							
	if( strcmp(file_ext,"jpg")==0 ||
		strcmp(file_ext,"jpeg")==0||
		strcmp(file_ext,"png")==0 ||
		strcmp(file_ext,"gif")==0 ||
		strcmp(file_ext,"bmp")==0 ){
		buffer_append_string_len(out, CONST_STR_LEN("<div id='fileviewicon' class='imgfileDiv bicon'>"));
	}
	else if( strcmp(file_ext,"mp3")==0 ||
			 strcmp(file_ext,"m4a")==0 ||
			 strcmp(file_ext,"m4r")==0 ||
			 strcmp(file_ext,"wav")==0 ){	
		use_http_connect = 1;
		buffer_append_string_len(out, CONST_STR_LEN("<div id='fileviewicon' class='audiofileDiv bicon'>"));
	}
	else if( strcmp(file_ext,"mp4")==0 ||
			 strcmp(file_ext,"rmvb")==0 ||
		 	 strcmp(file_ext,"m4v")==0 ||
			 strcmp(file_ext,"wmv")==0 ||
			 strcmp(file_ext,"avi")==0 ||
			 strcmp(file_ext,"mpg")==0 ||
			 strcmp(file_ext,"mpeg")==0 ||
			 strcmp(file_ext,"mkv")==0 ||
			 strcmp(file_ext,"mov")==0 ||
			 strcmp(file_ext,"flv")==0 ||
			 strcmp(file_ext,"3gp")==0 ||
			 strcmp(file_ext,"m2v")==0 ||
			 strcmp(file_ext,"rm")==0 ){
		use_http_connect = 1;
		buffer_append_string_len(out, CONST_STR_LEN("<div id='fileviewicon' class='videofileDiv bicon'>"));
	}
	else if(strcmp(file_ext,"doc")==0||strcmp(file_ext,"docx")==0)			
		buffer_append_string_len(out, CONST_STR_LEN("<div id='fileviewicon' class='docfileDiv bicon'>"));
	else if(strcmp(file_ext,"ppt")==0||strcmp(file_ext,"pptx")==0)
		buffer_append_string_len(out, CONST_STR_LEN("<div id='fileviewicon' class='pptfileDiv bicon'>"));
	else if(strcmp(file_ext,"xls")==0||strcmp(file_ext,"xlsx")==0)
		buffer_append_string_len(out, CONST_STR_LEN("<div id='fileviewicon' class='xlsfileDiv bicon'>"));
	else if(strcmp(file_ext,"pdf")==0)
		buffer_append_string_len(out, CONST_STR_LEN("<div id='fileviewicon' class='pdffileDiv bicon'>"));
	else
		buffer_append_string_len(out, CONST_STR_LEN("<div id='fileviewicon' class='fileDiv bicon'>"));
	
	buffer_append_string_len(out, CONST_STR_LEN("<div class='selectDiv sicon'></div>"));
	buffer_append_string_len(out, CONST_STR_LEN("<div class='selectHintDiv sicon'></div>"));
	buffer_append_string_len(out, CONST_STR_LEN("</div></div></td></tr><tr><td><div class='albuminfo' style='font-size:80%'>"));
	buffer_append_string_len(out, CONST_STR_LEN("<a id='list_item' qtype='1' isdir='0' playhref='"));

#if EMBEDDED_EANBLE
	char* webdav_http_port = nvram_get_webdav_http_port();
#else
	char* webdav_http_port = "8082";
#endif
	
	if(use_http_connect==1){
		buffer_append_string_len(out, CONST_STR_LEN("http://"));
		buffer_append_string_buffer(out, con->uri.authority);
		
		if( !strstr( con->uri.authority->ptr, ":" ) ){
			buffer_append_string_len(out, CONST_STR_LEN(":"));
			buffer_append_string(out, webdav_http_port);
		}
	}
	else{
		buffer_append_string_buffer(out, con->uri.scheme);
		buffer_append_string_len(out, CONST_STR_LEN("://"));
		buffer_append_string_buffer(out, con->uri.authority);
	}
	
	buffer_append_string_len(out, CONST_STR_LEN("/"));
	buffer_append_string_buffer(out, con->share_link_shortpath);
	buffer_append_string_len(out, CONST_STR_LEN("/"));
	buffer_append_string_buffer(out, con->share_link_filename);	
	buffer_append_string_len(out, CONST_STR_LEN("/"));
	buffer_append_string(out, filename);

	buffer_append_string_len(out, CONST_STR_LEN("' uhref='"));

	buffer_append_string_buffer(out, con->uri.scheme);
	buffer_append_string_len(out, CONST_STR_LEN("://"));
	buffer_append_string_buffer(out, con->uri.authority);
	buffer_append_string_len(out, CONST_STR_LEN("/"));
	buffer_append_string_buffer(out, con->share_link_shortpath);
	buffer_append_string_len(out, CONST_STR_LEN("/"));
	buffer_append_string_buffer(out, con->share_link_filename);	
	buffer_append_string_len(out, CONST_STR_LEN("/"));
	buffer_append_string(out, filename);
	
	buffer_append_string_len(out, CONST_STR_LEN("' title='"));
	buffer_append_string_buffer(out, buffer_filename);
	
	buffer_append_string_len(out, CONST_STR_LEN("' ext='"));
							
	buffer_append_string(out, file_ext);
	free(file_ext);
							
	buffer_append_string_len(out, CONST_STR_LEN("' freadonly='true' fhidden='false'>"));
	
	buffer_append_string_buffer( out, buffer_filename );
	buffer_append_string_len(out, CONST_STR_LEN("</a></div></td></tr>"));

	buffer_append_string_len(out, CONST_STR_LEN("<tr><td>"));
	buffer_append_string_len(out, CONST_STR_LEN("<input type='button' class='btnDownload' value='Downloads!'>"));
	buffer_append_string_len(out, CONST_STR_LEN("</td></tr>"));
	
	buffer_append_string_len(out, CONST_STR_LEN("</tbody></table></div>"));

	buffer_free(buffer_filename);
	
}