Пример #1
0
// be tolerant on errors
static int uwsgi_routing_func_cache_store(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
	struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;

	// overwrite previous run
	if (wsgi_req->cache_it) {
		uwsgi_buffer_destroy(wsgi_req->cache_it);
		wsgi_req->cache_it = NULL;		
	}

	if (wsgi_req->cache_it_to) {
		uwsgi_buffer_destroy(wsgi_req->cache_it_to);
		wsgi_req->cache_it_to = NULL;		
	}

	// build key and name
        char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

        wsgi_req->cache_it = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
        if (!wsgi_req->cache_it) return UWSGI_ROUTE_NEXT;
	
	if (urcc->name) {
		wsgi_req->cache_it_to = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->name, urcc->name_len);
		if (!wsgi_req->cache_it_to) {
			uwsgi_buffer_destroy(wsgi_req->cache_it);
			wsgi_req->cache_it = NULL;
		}
	}

	wsgi_req->cache_it_expires = urcc->expires;

	return UWSGI_ROUTE_NEXT;
	
}
Пример #2
0
// metricinc/metricdec/metricmul/metricdiv/metricset
static int uwsgi_routing_func_metricmath(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){

        struct uwsgi_router_metric_conf *urmc = (struct uwsgi_router_metric_conf *) ur->data2;

        char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

        struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->name, urmc->name_len);
        if (!ub) return UWSGI_ROUTE_BREAK;

        struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->value, urmc->value_len);
        if (!ub_val) {
               	uwsgi_buffer_destroy(ub);
               	return UWSGI_ROUTE_BREAK;
        }
	int64_t num = strtol(ub_val->buf, NULL, 10);
        uwsgi_buffer_destroy(ub_val);

        if (urmc->func(ub->buf, NULL, num)) {
                uwsgi_buffer_destroy(ub);
                return UWSGI_ROUTE_BREAK;
        }
        uwsgi_buffer_destroy(ub);
        return UWSGI_ROUTE_NEXT;
}
Пример #3
0
static int uwsgi_routing_func_expires(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){

        struct uwsgi_router_expires_conf *urec = (struct uwsgi_router_expires_conf *) ur->data2;

        char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

	uint64_t expires = 0;

	if (urec->filename) {

        	struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urec->filename, urec->filename_len);
        	if (!ub) return UWSGI_ROUTE_BREAK;

		struct stat st;
		if (stat(ub->buf, &st)) {
			uwsgi_buffer_destroy(ub);
			return UWSGI_ROUTE_BREAK;
		}

		expires = st.st_mtime;
		uwsgi_buffer_destroy(ub);

	}
	else if (urec->unixt) {
		struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urec->unixt, urec->unixt_len);
                if (!ub) return UWSGI_ROUTE_BREAK;

		expires = strtoul(ub->buf, NULL, 10);
		uwsgi_buffer_destroy(ub);
	}

	if (urec->value) {
		struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urec->value, urec->value_len);
		if (!ub) return UWSGI_ROUTE_BREAK;

		expires += atoi(ub->buf);
        	uwsgi_buffer_destroy(ub);
	}

	char expires_str[7 + 2 + 31];
        int len = uwsgi_http_date((time_t) expires, expires_str + 9);
        if (!len) return UWSGI_ROUTE_BREAK;

	memcpy(expires_str, "Expires: ", 9);

	uwsgi_additional_header_add(wsgi_req, expires_str, 9 + len);

        return UWSGI_ROUTE_NEXT;
}
Пример #4
0
static int uwsgi_routing_func_rewrite(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {

	char *tmp_qs = NULL;

	char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

	struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
        if (!ub) return UWSGI_ROUTE_BREAK;

	uint16_t path_info_len = ub->pos;
	uint16_t query_string_len = 0;
	
	char *query_string = memchr(ub->buf, '?', ub->pos);
	if (query_string) {
		path_info_len = query_string - ub->buf;
		query_string++;
		query_string_len = ub->pos - (path_info_len + 1);
		if (wsgi_req->query_string_len > 0) {
			tmp_qs = uwsgi_concat4n(query_string, query_string_len, "&", 1, wsgi_req->query_string, wsgi_req->query_string_len, "", 0);
			query_string = tmp_qs;
			query_string_len = strlen(query_string);
		}	
	}
	// over engineering, could be required in the future...
	else {
		if (wsgi_req->query_string_len > 0) {
			query_string = wsgi_req->query_string;
			query_string_len = wsgi_req->query_string_len;
		}
		else {
			query_string = "";
		}
	}

	char *ptr = uwsgi_req_append(wsgi_req, "PATH_INFO", 9, ub->buf, path_info_len);
        if (!ptr) goto clear;

	// set new path_info
	wsgi_req->path_info = ptr;
	wsgi_req->path_info_len = path_info_len;

	ptr = uwsgi_req_append(wsgi_req, "QUERY_STRING", 12, query_string, query_string_len);
	if (!ptr) goto clear;

	// set new query_string
	wsgi_req->query_string = ptr;
	wsgi_req->query_string_len = query_string_len;

	uwsgi_buffer_destroy(ub);
	if (tmp_qs) free(tmp_qs);
	if (ur->custom)
		return UWSGI_ROUTE_CONTINUE;
	return UWSGI_ROUTE_NEXT;

clear:
	uwsgi_buffer_destroy(ub);
	if (tmp_qs) free(tmp_qs);
	return UWSGI_ROUTE_BREAK;
}
Пример #5
0
Файл: ssi.c Проект: Algy/uwsgi
static int uwsgi_routing_func_ssi(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){

	struct uwsgi_buffer *ub = NULL;

        char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);

        struct uwsgi_buffer *ub_filename = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
        if (!ub_filename) goto end;

	struct uwsgi_buffer *ub_ssi = uwsgi_buffer_from_file(ub_filename->buf);
	uwsgi_buffer_destroy(ub_filename);
	if (!ub_ssi) goto end;

	ub = uwsgi_ssi_parse(wsgi_req, ub_ssi->buf, ub_ssi->pos);
	uwsgi_buffer_destroy(ub_ssi);
	if (!ub) goto end;

        if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end;
        if (uwsgi_response_add_content_length(wsgi_req, ub->pos)) goto end;
        if (uwsgi_response_add_content_type(wsgi_req, "text/html", 9)) goto end;

        uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos);
	
end:
	if (ub) uwsgi_buffer_destroy(ub);
        return UWSGI_ROUTE_BREAK;
}
Пример #6
0
static int uwsgi_ssh_routing(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
	// ssh://username[:password]@127.0.0.1:2222/tmp/foo.txt,username[:password]@127.0.0.1:2222/tmp/foobis.txt

	char *remote_url = NULL;

	char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
	uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);
	struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
	if (!ub) {
		uwsgi_error("uwsgi_ssh_routing()/uwsgi_routing_translate()");
		remote_url = ur->data;
	} else {
		remote_url = ub->buf;
	}

	remote_url = uwsgi_concat2(remote_url, ",");
	char *remote_pointer = remote_url;
	char *comma = NULL;
	struct uwsgi_ssh_mountpoint *usm = uwsgi_calloc(sizeof(struct uwsgi_ssh_mountpoint));
	int return_status = -1;

	while ((comma = strchr(remote_url, ',')) != NULL) {
		*comma = 0;

		if (uwsgi_ssh_url_parser(remote_url, &usm)) {
			uwsgi_log("[SSH] skipping malformed route %s\n", remote_url);
			return_status = 500;
			continue;
		}

		if (!(return_status = uwsgi_ssh_request_file(
					wsgi_req,
					usm->path,
					usm
		)))
		{
			goto end;
		} else {
			uwsgi_log("[SSH] route %s to %s returned %d. Engaging fail-over mechanism (if any)...\n",
				usm->remote, usm->path, return_status);
		}

		remote_url = comma + 1;
	}

	switch (return_status) {
		case 404:
			uwsgi_404(wsgi_req);
			break;

		case 500:
		default:
			uwsgi_500(wsgi_req);
	}

end:
	free(remote_pointer);
	uwsgi_buffer_destroy(ub);
	return UWSGI_OK;
}
Пример #7
0
static int uwsgi_routing_func_cache(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){

	struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2;

	char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);
	struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len);
        if (!ub) return UWSGI_ROUTE_BREAK;

	uint64_t valsize = 0;
	char *value = uwsgi_cache_magic_get(ub->buf, ub->pos, &valsize, urcc->name);
	uwsgi_buffer_destroy(ub);
	if (value) {
		if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto error;
		if (uwsgi_response_add_content_type(wsgi_req, urcc->content_type, urcc->content_type_len)) goto error;
		if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error;
		uwsgi_response_write_body_do(wsgi_req, value, valsize);
		free(value);
		if (ur->custom)
			return UWSGI_ROUTE_NEXT;
		return UWSGI_ROUTE_BREAK;
	}
	
	return UWSGI_ROUTE_NEXT;
error:
	free(value);
	return UWSGI_ROUTE_BREAK;
}
Пример #8
0
static int uwsgi_routing_func_xslt(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){

        struct uwsgi_router_xslt_conf *urxc = (struct uwsgi_router_xslt_conf *) ur->data2;

	char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);

	struct uwsgi_buffer *ub_doc = NULL;
	struct uwsgi_buffer *ub_stylesheet = NULL;
	struct uwsgi_buffer *ub_params = NULL;
	struct uwsgi_buffer *ub_content_type = NULL;

	ub_doc = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->doc, urxc->doc_len);
	if (!ub_doc) goto end;
	ub_stylesheet = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->stylesheet, urxc->stylesheet_len);
	if (!ub_stylesheet) goto end;

	if (urxc->params) {
		ub_params = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->params, urxc->params_len);
		if (!ub_params) goto end;
	}

	if (urxc->content_type) {
		ub_content_type = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->content_type, urxc->content_type_len);
		if (!ub_content_type) goto end;
	}

	int rlen;
        char *output = uwsgi_xslt_apply( ub_doc->buf, ub_stylesheet->buf, ub_params ? ub_params->buf : NULL, &rlen);
	if (!output) goto end;

        if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end;
        if (uwsgi_response_add_content_length(wsgi_req, rlen)) goto end;
        if (uwsgi_response_add_content_type(wsgi_req, urxc->content_type, urxc->content_type_len)) goto end;

        uwsgi_response_write_body_do(wsgi_req, output, rlen);
	xmlFree(output);

end:
	if (ub_doc) uwsgi_buffer_destroy(ub_doc);
	if (ub_stylesheet) uwsgi_buffer_destroy(ub_stylesheet);
	if (ub_params) uwsgi_buffer_destroy(ub_params);
	if (ub_content_type) uwsgi_buffer_destroy(ub_content_type);
        return UWSGI_ROUTE_BREAK;
}
Пример #9
0
static int uwsgi_routing_func_rpc_blob(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
        int ret = -1;
        // this is the list of args
        char *argv[UMAX8];
        // this is the size of each argument
        uint16_t argvs[UMAX8];
        // this is a placeholder for tmp uwsgi_buffers
        struct uwsgi_buffer *ubs[UMAX8];

        char **r_argv = (char **) ur->data2;
        uint16_t *r_argvs = (uint16_t *) ur->data3;

        char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

        uint64_t i;
        for(i=0;i<ur->custom;i++) {
                ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
                if (!ubs[i]) goto end;
                argv[i] = ubs[i]->buf;
                argvs[i] = ubs[i]->pos;
        }

        // ok we now need to check it it is a local call or a remote one
        char *func = uwsgi_str(ur->data);
        char *remote = NULL;
        char *at = strchr(func, '@');
        if (at) {
                *at = 0;
                remote = at+1;
        }
        uint16_t size;
        char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
        free(func);
        if (!response) goto end;

        ret = UWSGI_ROUTE_NEXT;

	// optimization
	if (!wsgi_req->headers_sent) {
        	if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {free(response) ; goto end;}
        	if (uwsgi_response_add_connection_close(wsgi_req)) {free(response) ; goto end;}
	}
        uwsgi_response_write_body_do(wsgi_req, response, size);
        free(response);

end:
        for(i=0;i<ur->custom;i++) {
                if (ubs[i] != NULL) {
                        uwsgi_buffer_destroy(ubs[i]);
                }
        }
        return ret;
}
Пример #10
0
int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {

	char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

	struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
        if (!ub) return UWSGI_ROUTE_BREAK;

	uwsgi_file_serve(wsgi_req, ub->buf, ub->pos, NULL, 0, 1);
	uwsgi_buffer_destroy(ub);
	return UWSGI_ROUTE_BREAK;
}
Пример #11
0
int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {

	char buf[32768];
	struct stat st;
	int ret = UWSGI_ROUTE_BREAK;
	size_t remains = 0;

	struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2;

        char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

        struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->filename, urfc->filename_len);
        if (!ub) return UWSGI_ROUTE_BREAK;

	int fd = open(ub->buf, O_RDONLY);
	if (fd < 0) {
		if (ur->custom)
			ret = UWSGI_ROUTE_NEXT;
		goto end; 
	}

	if (fstat(fd, &st)) {
		goto end2;
	}

	struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
        if (!ub_s) goto end2;

	// static file - don't update avg_rt after request
	wsgi_req->do_not_account_avg_rt = 1;

	if (urfc->no_headers) {
		uwsgi_buffer_destroy(ub_s);
		goto send;
	}

	if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
		uwsgi_buffer_destroy(ub_s);
		goto end2;
	}
	uwsgi_buffer_destroy(ub_s);
	if (!urfc->no_cl) {
		if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2;
	}
	if (urfc->mime) {
		size_t mime_type_len = 0;
		char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len);
		if (mime_type) {
			if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2;
		}
		else {
			if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
		}
	}
	else {
		if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
	}

send:
	
	remains = st.st_size;
	while(remains) {
		ssize_t rlen = read(fd, buf, UMIN(32768, remains));
		if (rlen <= 0) goto end2;
		if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) goto end2;
		remains -= rlen;
	}
	
end2:
	close(fd);
end:
        uwsgi_buffer_destroy(ub);
        return ret;
}
Пример #12
0
int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {

        struct stat st;
        int ret = UWSGI_ROUTE_BREAK;

        struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2;

        char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

        struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->filename, urfc->filename_len);
        if (!ub) return UWSGI_ROUTE_BREAK;

        int fd = open(ub->buf, O_RDONLY);
        if (fd < 0) {
                if (ur->custom)
                        ret = UWSGI_ROUTE_NEXT;
                goto end;
        }

        if (fstat(fd, &st)) {
                goto end2;
        }

        struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len);
        if (!ub_s) goto end2;

        // static file - don't update avg_rt after request
        wsgi_req->do_not_account_avg_rt = 1;

	if (urfc->no_headers) {
                uwsgi_buffer_destroy(ub_s);
		goto send;
	}

        if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) {
                uwsgi_buffer_destroy(ub_s);
                goto end2;
        }
        uwsgi_buffer_destroy(ub_s);
        if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2;
        if (urfc->mime) {
                size_t mime_type_len = 0;
                char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len);
                if (mime_type) {
                        if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2;
                }
                else {
                        if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
                }
        }
        else {
                if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2;
        }

send:

	if (!wsgi_req->headers_sent) {
                if (uwsgi_response_write_headers_do(wsgi_req)) goto end2;
        }

	if (wsgi_req->socket->can_offload) {
		if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, st.st_size)) {
                        wsgi_req->via = UWSGI_VIA_OFFLOAD;
                        wsgi_req->response_size += st.st_size;
                	// the fd will be closed by the offload engine
			goto end;
		}
	}

        if (!uwsgi_simple_sendfile(wsgi_req, fd, 0, st.st_size)) {
                wsgi_req->via = UWSGI_VIA_SENDFILE;
                wsgi_req->response_size += st.st_size;
        }

end2:
        close(fd);
end:
        uwsgi_buffer_destroy(ub);
        return ret;
}
Пример #13
0
static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {

	// mark a route request
        wsgi_req->via = UWSGI_VIA_ROUTE;

	// get the http address from the route
	char *addr = ur->data;

	struct uwsgi_buffer *ub_url = NULL;
	if (ur->data3_len) {
		char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        	uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);
		ub_url = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data3, ur->data3_len);
        	if (!ub_url) return UWSGI_ROUTE_BREAK;
	}


	// convert the wsgi_request to an http proxy request
	struct uwsgi_buffer *ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);	
	if (!ub) {
		if (ub_url) uwsgi_buffer_destroy(ub_url);
		uwsgi_log("unable to generate http request for %s\n", addr);
                return UWSGI_ROUTE_NEXT;
	}

	if (ub_url) uwsgi_buffer_destroy(ub_url);

	// amount of body to send
	size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_remains;
	// append remaining body...
	if (wsgi_req->proto_parser_remains > 0) {
		if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) {
			uwsgi_buffer_destroy(ub);
			uwsgi_log("unable to generate http request for %s\n", addr);
               		return UWSGI_ROUTE_NEXT;
		}
		wsgi_req->proto_parser_remains = 0;
	}

	// ok now if have offload threads, directly use them
	if (!wsgi_req->post_file && !ur->custom && wsgi_req->socket->can_offload) {
		// append buffered body
		if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) {
			if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) {
				uwsgi_buffer_destroy(ub);
				uwsgi_log("unable to generate http request for %s\n", addr);
               			return UWSGI_ROUTE_NEXT;
			}
		}
        	if (!uwsgi_offload_request_net_do(wsgi_req, addr, ub)) {
                	wsgi_req->via = UWSGI_VIA_OFFLOAD;
			wsgi_req->status = 202;
			return UWSGI_ROUTE_BREAK;
                }
	}

	if (uwsgi_proxy_nb(wsgi_req, addr, ub, remains, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
		uwsgi_log("error routing request to http server %s\n", addr);
	}

	uwsgi_buffer_destroy(ub);

	return UWSGI_ROUTE_BREAK;

}
Пример #14
0
static int uwsgi_routing_func_fcgi(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
	struct uwsgi_buffer *ub = NULL, *headers = NULL;
	int ret = UWSGI_ROUTE_BREAK;
	int inbody = 0;

	// mark a route request
        wsgi_req->via = UWSGI_VIA_ROUTE;

	char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

	struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
	if (!ub_addr) return UWSGI_ROUTE_BREAK;

	// convert the wsgi_request to an fcgi request
	ub = uwsgi_to_fastcgi(wsgi_req, ur->custom ? FCGI_AUTHORIZER : FCGI_RESPONDER);

	if (!ub) {
		uwsgi_log("unable to generate fcgi request for %s\n", ub_addr->buf);
		uwsgi_buffer_destroy(ub_addr);
                return UWSGI_ROUTE_BREAK;
	}

	int fd = 0;

	fd = fcgi_send(wsgi_req, ub_addr->buf, ub, uwsgi.socket_timeout);
	uwsgi_buffer_destroy(ub);
	ub = NULL;

	if (fd == -1) {
		uwsgi_log("error routing request to fcgi server %s\n", ub_addr->buf);
		goto end;
	}

	headers = uwsgi_buffer_new(uwsgi.page_size);
	char buf[8192];
	char *ptr = buf;//, *rptr = NULL;
	ssize_t left = 0, n = 0, p = 0;
	int oversized = 0, done = 0;


	for (;;) {
                int r = uwsgi_waitfd(fd, uwsgi.socket_timeout);
                if (r <= 0) goto end;

		ssize_t rlen = 0;
		/* Amount left in buffer is not a full record header, so we
		 * need to fudge the next read to append to the current buffer. */
		if ((sizeof(buf) - (ptr - buf) - left) < 8) {
			memmove(buf, ptr, left);
			ptr = buf;
		}

		if ((!done || !left) && (sizeof(buf) - (ptr - buf) - left) > 0) {
			rlen = read(fd, ptr + left, sizeof(buf) - (ptr - buf) - left);

			if (rlen < 0)
				break;
			if (rlen == 0)
				done = 1;
		}

		if (done && !left) {
			uwsgi_log("[fastcgi] %s: truncated response\n", ub_addr->buf);
			goto end;
		}

		if (oversized) { /* n more bytes left in stdout record */
			if (uwsgi_response_write_body_do(wsgi_req, (char *) ptr, n > rlen ? rlen : n))
				goto end;

			if (n > rlen) {
				n -= rlen;
				ptr = buf;
				left = 0;
				continue;
			} else if (n == rlen) {
				oversized = 0;
				left = 0;
				ptr = buf;
				continue;
			} else {
				ptr += n;
				left = rlen - n;
				oversized = 0;
				continue;
			}
		} else {
			left += rlen;
		}

		while (left >= 8 && !oversized) {
			if (p) {
				if (left >= p) {
					left -= p;
					ptr += p;
					p = 0;
					continue;
				}
			}

			if (ptr[0] != 1) { /* version */
				uwsgi_log("[fastcgi] %s: unexpected protocol version %u\n", ub_addr->buf, (unsigned int) ptr[0]);
				goto end;
			}
			if (ptr[2] != 0 || ptr[3] != 1) { /* reqid */
				uwsgi_log("[fastcgi] %s: unexpected request id %d\n", ub_addr->buf, (int) ptr[3]);
				goto end;
			}
			n = (int)((unsigned char *)ptr)[4] << 8 | (int)((unsigned char *)ptr)[5];
			p = (int)((unsigned char *)ptr)[6];

			int type = ptr[1];
			ptr += 8;
			left -= 8;
			switch (type) {
			case FCGI_END_REQUEST:
				break;

			case FCGI_STDERR:
				uwsgi_log("[fastcgi] %s: stderr: %*s\n", ub_addr->buf, (int) (n > left ? left : n), ptr);
				if ((n + p) > left) {
					uwsgi_log("[fastcgi] %s: short record, (%d + %d) < %d\n", ub_addr->buf, (int) n, (int) p, (int) left);
					goto end;
				}
				ptr += (n + p);
				left -= (n + p);
				break;

			case FCGI_STDOUT:
				if (n == 0)
					goto end;

				if (!inbody) {
					ssize_t now = n < left ? n : left;
					if (uwsgi_buffer_append(headers, (char *) ptr, now))
						goto end;

					// check if we have a full HTTP response
					if (uwsgi_is_full_http(headers)) {
						inbody = 1;
						if (ur->custom && http_status_code(headers->buf, headers->pos) == 200) {
							ret = UWSGI_ROUTE_NEXT;
							/* XXX - add Variable headers */
							goto end;
						} else {
							uwsgi_blob_to_response(wsgi_req, headers->buf, headers->pos);
						}
						uwsgi_buffer_destroy(headers);
						headers = NULL;
					} else {
						/* we can't buffer > sizeof(buf) of headers - shouldn't be
						 * needed anyway. */
						if (n > left) {
							uwsgi_log("[fastcgi] %s: headers too long (%d)\n", ub_addr->buf, (int) n);
							goto end;
						}
					}

					ptr += now;
					left -= now;
					n -= now;
				}

				if (n) {
					ssize_t nleft = n > left ? left : n; /* min(left in buffer, record size) */
					if (uwsgi_response_write_body_do(wsgi_req, (char *) ptr, nleft))
						goto end;
					n -= nleft;
					left -= nleft;
					ptr += nleft;

					if (n > left) { /* more data in this record */
						oversized = 1;
						left = 0;
						ptr = buf;
						continue;
					}
				}

				break;

			default:
				uwsgi_log("[fastcgi] %s: unknown record type %d\n", ub_addr->buf, (int) ptr[1]);
				goto end;
			}
		}

		if (left == 0)
			ptr = buf;
	}

end:
	if (fd) close(fd);
	if (ub) uwsgi_buffer_destroy(ub);
	if (ub_addr) uwsgi_buffer_destroy(ub_addr);
	if (headers) uwsgi_buffer_destroy(headers);
	return ret;
}
Пример #15
0
// "next" || "continue" || "break(.*)" || "goon" || "goto .+"
static int uwsgi_routing_func_rpc_ret(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
        int ret = -1;
        // this is the list of args
        char *argv[UMAX8];
        // this is the size of each argument
        uint16_t argvs[UMAX8];
        // this is a placeholder for tmp uwsgi_buffers
        struct uwsgi_buffer *ubs[UMAX8];

        char **r_argv = (char **) ur->data2;
        uint16_t *r_argvs = (uint16_t *) ur->data3;

        char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

        uint64_t i;
        for(i=0;i<ur->custom;i++) {
                ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]);
                if (!ubs[i]) goto end;
                argv[i] = ubs[i]->buf;
                argvs[i] = ubs[i]->pos;
        }

        // ok we now need to check it it is a local call or a remote one
        char *func = uwsgi_str(ur->data);
        char *remote = NULL;
        char *at = strchr(func, '@');
        if (at) {
                *at = 0;
                remote = at+1;
        }
        uint16_t size;
        char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size);
        free(func);
        if (!response) goto end;

        ret = UWSGI_ROUTE_CONTINUE;
	if (!uwsgi_strncmp(response, size, "next", 4 )) {
        	ret = UWSGI_ROUTE_NEXT;
	}
	else if (!uwsgi_strncmp(response, size, "continue", 8 )) {
        	ret = UWSGI_ROUTE_CONTINUE;
	}
	else if (!uwsgi_starts_with(response, size, "break", 5 )) {
        	ret = UWSGI_ROUTE_BREAK;
		if (size > 6) {
			if (uwsgi_response_prepare_headers(wsgi_req, response+6, size-6)) goto end0;
                	if (uwsgi_response_add_connection_close(wsgi_req)) goto end0;
                	if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end0;
                	// no need to check for return value
                	uwsgi_response_write_headers_do(wsgi_req);
		}
	}
	else if (!uwsgi_starts_with(response, size, "goto ", 5)) {
		ret = UWSGI_ROUTE_BREAK;
		if (size > 5) {
		 	// find the label
        		struct uwsgi_route *routes = uwsgi.routes;
        		while(routes) {
                		if (!routes->label) goto next;
                		if (!uwsgi_strncmp(routes->label, routes->label_len, response+5, size-5)) {
					ret = UWSGI_ROUTE_NEXT;
                        		wsgi_req->route_goto = routes->pos;
                        		goto found;
                		}
next:
               			routes = routes->next;
        		}
			goto end0;	
found:
        		if (wsgi_req->route_goto <= wsgi_req->route_pc) {
                		wsgi_req->route_goto = 0;
                		uwsgi_log("[uwsgi-route] ERROR \"goto\" instruction can only jump forward (check your label !!!)\n");
				ret = UWSGI_ROUTE_BREAK;
        		}
		}
	}

end0:
        free(response);

end:
        for(i=0;i<ur->custom;i++) {
                if (ubs[i] != NULL) {
                        uwsgi_buffer_destroy(ubs[i]);
                }
        }
        return ret;
}
Пример #16
0
static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
	
	struct uwsgi_buffer *ub = NULL;

	// mark a route request
        wsgi_req->via = UWSGI_VIA_ROUTE;

	char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

	struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
	if (!ub_addr) return UWSGI_ROUTE_BREAK;

	struct uwsgi_buffer *ub_url = NULL;
	if (ur->data3_len) {
		ub_url = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data3, ur->data3_len);
        	if (!ub_url) {
			uwsgi_buffer_destroy(ub_addr);
			return UWSGI_ROUTE_BREAK;
		}
	}

	// convert the wsgi_request to an http proxy request
	if (ur->custom & 0x02) {
		ub = uwsgi_buffer_new(uwsgi.page_size);
	}
	else if (ur->custom & 0x04) {
		ub = uwsgi_to_http_dumb(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
	}
	else {
		ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);	
	}

	if (!ub) {
		if (ub_url) uwsgi_buffer_destroy(ub_url);
		uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
		uwsgi_buffer_destroy(ub_addr);
                return UWSGI_ROUTE_NEXT;
	}

	if (ub_url) uwsgi_buffer_destroy(ub_url);

	// amount of body to send
	size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_remains;
	// append remaining body...
	if (wsgi_req->proto_parser_remains > 0) {
		if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) {
			uwsgi_buffer_destroy(ub);
			uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
			uwsgi_buffer_destroy(ub_addr);
               		return UWSGI_ROUTE_NEXT;
		}
		wsgi_req->post_pos += wsgi_req->proto_parser_remains;
		wsgi_req->proto_parser_remains = 0;
	}

	// ok now if have offload threads, directly use them
	if (!wsgi_req->post_file && !(ur->custom & 0x01) && wsgi_req->socket->can_offload) {
		// append buffered body
		if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) {
			if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) {
				uwsgi_buffer_destroy(ub);
				uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
				uwsgi_buffer_destroy(ub_addr);
               			return UWSGI_ROUTE_NEXT;
			}
		}

		// if we have a CONNECT request, let's confirm it to the client
		if (ur->custom & 0x02) {
			if (uwsgi_response_prepare_headers(wsgi_req, "200 Connection established", 26)) goto end;
                        // no need to check for return value
                        uwsgi_response_write_headers_do(wsgi_req);	
		}

        	if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) {
                	wsgi_req->via = UWSGI_VIA_OFFLOAD;
			wsgi_req->status = 202;
			uwsgi_buffer_destroy(ub_addr);
			return UWSGI_ROUTE_BREAK;
                }
	}

	if (uwsgi_proxy_nb(wsgi_req, ub_addr->buf, ub, remains, uwsgi.socket_timeout)) {
		uwsgi_log("error routing request to http server %s\n", ub_addr->buf);
	}

end:
	uwsgi_buffer_destroy(ub);
	uwsgi_buffer_destroy(ub_addr);

	return UWSGI_ROUTE_BREAK;

}
Пример #17
0
static int uwsgi_routing_func_memcached(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
	// this is the buffer for the memcached response
	char buf[MEMCACHED_BUFSIZE];
	size_t i;
	char last_char = 0;

	struct uwsgi_router_memcached_conf *urmc = (struct uwsgi_router_memcached_conf *) ur->data2;

	char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
        uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

	struct uwsgi_buffer *ub_key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->key, urmc->key_len);
        if (!ub_key) return UWSGI_ROUTE_BREAK;

	int fd = uwsgi_connect(urmc->addr, 0, 1);
	if (fd < 0) { uwsgi_buffer_destroy(ub_key) ; goto end; }

        // wait for connection;
        int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
        if (ret <= 0) {
		uwsgi_buffer_destroy(ub_key) ;
		close(fd);
		goto end;
        }

	// build the request and send it
	char *cmd = uwsgi_concat3n("get ", 4, ub_key->buf, ub_key->pos, "\r\n", 2);
	if (uwsgi_write_true_nb(fd, cmd, 6+ub_key->pos, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) {
		uwsgi_buffer_destroy(ub_key);
		free(cmd);
		close(fd);
		goto end;
	}
	uwsgi_buffer_destroy(ub_key);
	free(cmd);

	// ok, start reading the response...
	// first we need to get a full line;
	size_t found = 0;
	size_t pos = 0;
	for(;;) {
		ssize_t len = read(fd, buf + pos, MEMCACHED_BUFSIZE - pos);
		if (len > 0) {
			pos += len;
			goto read;
		}
		if (len < 0) {
			if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) goto wait;
		}
		close(fd);
		goto end;
wait:
		ret = uwsgi.wait_read_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
		// when we have a chunk try to read the first line
		if (ret > 0) {
			len = read(fd, buf + pos, MEMCACHED_BUFSIZE - pos);
			if (len > 0) {
				pos += len;
				goto read;
			}
		}
		close(fd);
		goto end;
read:
		for(i=0;i<pos;i++) {
			if (last_char == '\r' && buf[i] == '\n') {
				found = i-1;
				break;
			}
			last_char = buf[i];
		}
		if (found) break;
	}

	// ok parse the first line
	size_t response_size = memcached_firstline_parse(buf, found);

	if (response_size == 0) {
		close(fd);
		goto end;
	}

	if (urmc->type_num == 1) {
		if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) { close(fd); goto end; }
		if (uwsgi_response_add_content_type(wsgi_req, urmc->content_type, urmc->content_type_len)) { close(fd); goto end; }
		if (uwsgi_response_add_content_length(wsgi_req, response_size)) { close(fd); goto end; }
	}
	size_t remains = pos-(found+2);
	if (remains >= response_size) {
		uwsgi_response_write_body_do(wsgi_req, buf+found+2, response_size);
		close(fd);
		goto end;
	}

	// send what we have
	if (uwsgi_response_write_body_do(wsgi_req, buf+found+2, remains)) {
		close(fd);
		goto end;
	}

	// and now start reading til the output is consumed
	response_size -= remains;
	while(response_size > 0) {
		ssize_t len = read(fd, buf, UMIN(MEMCACHED_BUFSIZE, response_size));
		if (len > 0) goto write;
		if (len < 0) {
                        if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) goto wait2;
                }
		goto error;
wait2:
		ret = uwsgi.wait_read_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]);
		if (ret > 0) {
                        len = read(fd, buf, UMIN(MEMCACHED_BUFSIZE, response_size));
			if (len > 0) goto write;
		}
		goto error;
write:
		if (uwsgi_response_write_body_do(wsgi_req, buf, len)) {
			goto error;
        	}
		response_size -= len;
	}

	close(fd);
	return UWSGI_ROUTE_BREAK;

error:
	close(fd);
	
end:
	if (ur->custom)
        	return UWSGI_ROUTE_NEXT;

	return UWSGI_ROUTE_BREAK;
}
Пример #18
0
static int uwsgi_routing_func_hash(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {

    struct uwsgi_router_hash_conf *urhc = (struct uwsgi_router_hash_conf *) ur->data2;

    struct uwsgi_hash_algo *uha = uwsgi_hash_algo_get(urhc->algo);
    if (!uha) {
        uwsgi_log("[uwsgi-hash-router] unable to find hash algo \"%s\"\n", urhc->algo);
        return UWSGI_ROUTE_BREAK;
    }

    char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
    uint16_t *subject_len = (uint16_t *)  (((char *)(wsgi_req))+ur->subject_len);

    struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urhc->key, urhc->key_len);
    if (!ub) return UWSGI_ROUTE_BREAK;

    uint32_t h = uha->func(ub->buf, ub->pos);
    uwsgi_buffer_destroy(ub);

    // now count the number of items
    uint32_t items = 1;
    size_t i, ilen = urhc->items_len;
    for(i=0; i<ilen; i++) {
        if (urhc->items[i] == ';') items++;
    }

    // skip last semicolon
    if (urhc->items[ilen-1] == ';') items--;

    uint32_t hashed_result = h % items;
    uint32_t found = 0;
    char *value = urhc->items;
    uint16_t vallen = 0;
    for(i=0; i<ilen; i++) {
        if (!value) {
            value = urhc->items + i;
        }
        if (urhc->items[i] == ';') {
            if (found == hashed_result) {
                vallen = (urhc->items+i) - value;
                break;
            }
            value = NULL;
            found++;
        }
    }

    if (vallen == 0) {
        // first item
        if (hashed_result == 0) {
            value = urhc->items;
            vallen = urhc->items_len;
        }
        // last item
        else {
            vallen = (urhc->items + urhc->items_len) - value;
        }
    }

    if (!vallen) {
        uwsgi_log("[uwsgi-hash-router] BUG !!! unable to hash items\n");
        return UWSGI_ROUTE_BREAK;
    }

    if (!uwsgi_req_append(wsgi_req, urhc->var, urhc->var_len, value, vallen)) {
        uwsgi_log("[uwsgi-hash-router] unable to append hash var to the request\n");
        return UWSGI_ROUTE_BREAK;
    }

    return UWSGI_ROUTE_NEXT;
}
Пример #19
0
static int uwsgi_routing_func_xmldir(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){
	char **subject;
	uint16_t *subject_len;
	char *dirname;
	struct uwsgi_buffer *ub;
	char *name = NULL;
	char *path = NULL;
	int i;
	int n;
	struct dirent **tasklist;
	xmlDoc *rdoc;
	xmlNode *rtree;
	xmlNodePtr entrynode;
	char *path_info = NULL;
	struct stat sb;
	size_t sizebuf_len;
	char *sizebuf;
	char timebuf[20];
	int xlen = 0;

	subject = (char **) (((char *)(wsgi_req))+ur->subject);
	subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
	ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len,
	    ur->data, ur->data_len);
	if (!ub) {
		uwsgi_500(wsgi_req);
		return UWSGI_ROUTE_BREAK;
	}
	dirname = ub->buf;

	path_info = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len,
	    "", 1);

	n = scandir(dirname, &tasklist, 0, alphasort);
	if (n < 0) {
		uwsgi_404(wsgi_req);
		goto out;
	}

	rdoc = xmlNewDoc(BAD_CAST "1.0");
	rtree = xmlNewNode(NULL, BAD_CAST "index");
	xmlNewProp(rtree, BAD_CAST "path", BAD_CAST path_info);
	xmlDocSetRootElement(rdoc, rtree);

	for(i = 0; i < n; i++) {
		if ((strcmp(tasklist[i]->d_name, ".") == 0) ||
		    (strcmp(tasklist[i]->d_name, "..") == 0)) {
			goto next_entry;
		}

		path = uwsgi_concat3(dirname, "/", tasklist[i]->d_name);
		if (lstat(path, &sb) == -1) {
			goto next_entry;
		}

		name = to_utf8(conf.codeset, tasklist[i]->d_name);
		if (name == NULL) {
			goto next_entry;
		}

		if (S_ISDIR(sb.st_mode)) {
			entrynode = xmlNewTextChild(rtree, NULL,
			    BAD_CAST "directory", BAD_CAST name);
		} else if (S_ISREG(sb.st_mode)) {
			entrynode = xmlNewTextChild(rtree, NULL,
			    BAD_CAST "file", BAD_CAST name);
		} else {
			/* skip everything but directories and regular files */
			goto next_entry;
		}

		sizebuf_len = snprintf(NULL, 0, "%jd", (intmax_t) sb.st_size);
		sizebuf = uwsgi_malloc(sizebuf_len + 1);
		snprintf(sizebuf, sizebuf_len + 1, "%jd", (intmax_t) sb.st_size);
		xmlNewProp(entrynode, BAD_CAST "size", BAD_CAST sizebuf);
		free(sizebuf);

		strftime(timebuf, sizeof (timebuf), "%Y-%m-%dT%H:%M:%S",
		    localtime(&sb.st_mtime));
		xmlNewProp(entrynode, BAD_CAST "mtime", BAD_CAST timebuf);

next_entry:
		free(path);
		path = NULL;
		free(tasklist[i]);
		free(name);
		name = NULL;
	}

	free(tasklist);

	xmlChar *xmlbuf;
	xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1);

	uwsgi_response_prepare_headers(wsgi_req,"200 OK", 6);
	uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen);

	xmlFreeDoc(rdoc);
	xmlFree(xmlbuf);

out:
	uwsgi_buffer_destroy(ub);
	free(path_info);

	return UWSGI_ROUTE_BREAK;
}