mod_dir.c revision fd0edaa8e3d4dd67d0604ccef2e96b071db96643
af84459fbf938e508fd10b01cb8d699c79083813takashi/* ====================================================================
af84459fbf938e508fd10b01cb8d699c79083813takashi * Copyright (c) 1995-1999 The Apache Group. All rights reserved.
af84459fbf938e508fd10b01cb8d699c79083813takashi *
af84459fbf938e508fd10b01cb8d699c79083813takashi * Redistribution and use in source and binary forms, with or without
af84459fbf938e508fd10b01cb8d699c79083813takashi * modification, are permitted provided that the following conditions
af84459fbf938e508fd10b01cb8d699c79083813takashi * are met:
af84459fbf938e508fd10b01cb8d699c79083813takashi *
fed47023e9be04c612b5f6d4a5ee2b8e7c587181rbowen * 1. Redistributions of source code must retain the above copyright
af84459fbf938e508fd10b01cb8d699c79083813takashi * notice, this list of conditions and the following disclaimer.
af84459fbf938e508fd10b01cb8d699c79083813takashi *
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * 2. Redistributions in binary form must reproduce the above copyright
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * notice, this list of conditions and the following disclaimer in
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * the documentation and/or other materials provided with the
d29d9ab4614ff992b0e8de6e2b88d52b6f1f153erbowen * distribution.
af84459fbf938e508fd10b01cb8d699c79083813takashi *
af84459fbf938e508fd10b01cb8d699c79083813takashi * 3. All advertising materials mentioning features or use of this
d229f940abfb2490dee17979e9a5ff31b7012eb5rbowen * software must display the following acknowledgment:
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * "This product includes software developed by the Apache Group
af84459fbf938e508fd10b01cb8d699c79083813takashi * for use in the Apache HTTP server project (http://www.apache.org/)."
af84459fbf938e508fd10b01cb8d699c79083813takashi *
af84459fbf938e508fd10b01cb8d699c79083813takashi * 4. The names "Apache Server" and "Apache Group" must not be used to
3f08db06526d6901aa08c110b5bc7dde6bc39905nd * endorse or promote products derived from this software without
af84459fbf938e508fd10b01cb8d699c79083813takashi * prior written permission. For written permission, please contact
af84459fbf938e508fd10b01cb8d699c79083813takashi * apache@apache.org.
f086b4b402fa9a2fefc7dda85de2a3cc1cd0a654rjung *
af84459fbf938e508fd10b01cb8d699c79083813takashi * 5. Products derived from this software may not be called "Apache"
af84459fbf938e508fd10b01cb8d699c79083813takashi * nor may "Apache" appear in their names without prior written
af84459fbf938e508fd10b01cb8d699c79083813takashi * permission of the Apache Group.
af84459fbf938e508fd10b01cb8d699c79083813takashi *
af84459fbf938e508fd10b01cb8d699c79083813takashi * 6. Redistributions of any form whatsoever must retain the following
3c13a815670b54d1c17bf02954f7d2b066cde95cnd * acknowledgment:
3c13a815670b54d1c17bf02954f7d2b066cde95cnd * "This product includes software developed by the Apache Group
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen * for use in the Apache HTTP server project (http://www.apache.org/)."
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe *
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
fed47023e9be04c612b5f6d4a5ee2b8e7c587181rbowen * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
af84459fbf938e508fd10b01cb8d699c79083813takashi * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
af84459fbf938e508fd10b01cb8d699c79083813takashi * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
af84459fbf938e508fd10b01cb8d699c79083813takashi * OF THE POSSIBILITY OF SUCH DAMAGE.
af84459fbf938e508fd10b01cb8d699c79083813takashi * ====================================================================
af84459fbf938e508fd10b01cb8d699c79083813takashi *
af84459fbf938e508fd10b01cb8d699c79083813takashi * This software consists of voluntary contributions made by many
af84459fbf938e508fd10b01cb8d699c79083813takashi * individuals on behalf of the Apache Group and was originally based
af84459fbf938e508fd10b01cb8d699c79083813takashi * on public domain software written at the National Center for
fed47023e9be04c612b5f6d4a5ee2b8e7c587181rbowen * Supercomputing Applications, University of Illinois, Urbana-Champaign.
af84459fbf938e508fd10b01cb8d699c79083813takashi * For more information on the Apache Group and the Apache HTTP server
af84459fbf938e508fd10b01cb8d699c79083813takashi * project, please see <http://www.apache.org/>.
af84459fbf938e508fd10b01cb8d699c79083813takashi *
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe */
af84459fbf938e508fd10b01cb8d699c79083813takashi
30471a4650391f57975f60bbb6e4a90be7b284bfhumbedooh/*
af84459fbf938e508fd10b01cb8d699c79083813takashi * mod_dir.c: handle default index files, and trailing-/ redirects
af84459fbf938e508fd10b01cb8d699c79083813takashi */
fed47023e9be04c612b5f6d4a5ee2b8e7c587181rbowen
af84459fbf938e508fd10b01cb8d699c79083813takashi#include "httpd.h"
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe#include "http_config.h"
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe#include "http_core.h"
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe#include "http_request.h"
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe#include "http_protocol.h"
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe#include "http_log.h"
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe#include "http_main.h"
9a58dc6a2b26ec128b1270cf48810e705f1a90dbsf#include "util_script.h"
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowemodule MODULE_VAR_EXPORT dir_module;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
fed47023e9be04c612b5f6d4a5ee2b8e7c587181rbowentypedef struct dir_config_struct {
78f97ce162b66a0dbfd7af4dcd9984f162569b04minfrin array_header *index_names;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe} dir_config_rec;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe#define DIR_CMD_PERMS OR_INDEXES
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowestatic const char *add_index(cmd_parms *cmd, void *dummy, char *arg)
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe{
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe dir_config_rec *d = dummy;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
fed47023e9be04c612b5f6d4a5ee2b8e7c587181rbowen if (!d->index_names) {
fed47023e9be04c612b5f6d4a5ee2b8e7c587181rbowen d->index_names = ap_make_array(cmd->pool, 2, sizeof(char *));
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe }
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe *(char **)ap_push_array(d->index_names) = arg;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe return NULL;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe}
4bebf996eb7002ebfe897d46a0e0572390604a77nd
4bebf996eb7002ebfe897d46a0e0572390604a77ndstatic const command_rec dir_cmds[] =
4bebf996eb7002ebfe897d46a0e0572390604a77nd{
4bebf996eb7002ebfe897d46a0e0572390604a77nd {"DirectoryIndex", add_index, NULL,
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe DIR_CMD_PERMS, ITERATE,
4bebf996eb7002ebfe897d46a0e0572390604a77nd "a list of file names"},
9534272616b71aaea50aeec4162e749a96aebd7fsf {NULL}
4bebf996eb7002ebfe897d46a0e0572390604a77nd};
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
af84459fbf938e508fd10b01cb8d699c79083813takashistatic void *create_dir_config(pool *p, char *dummy)
af84459fbf938e508fd10b01cb8d699c79083813takashi{
af84459fbf938e508fd10b01cb8d699c79083813takashi dir_config_rec *new =
af84459fbf938e508fd10b01cb8d699c79083813takashi (dir_config_rec *) ap_pcalloc(p, sizeof(dir_config_rec));
af84459fbf938e508fd10b01cb8d699c79083813takashi
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe new->index_names = NULL;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe return (void *) new;
fed47023e9be04c612b5f6d4a5ee2b8e7c587181rbowen}
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowestatic void *merge_dir_configs(pool *p, void *basev, void *addv)
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe{
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe dir_config_rec *new = (dir_config_rec *) ap_pcalloc(p, sizeof(dir_config_rec));
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe dir_config_rec *base = (dir_config_rec *) basev;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe dir_config_rec *add = (dir_config_rec *) addv;
fed47023e9be04c612b5f6d4a5ee2b8e7c587181rbowen
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe new->index_names = add->index_names ? add->index_names : base->index_names;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe return new;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe}
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowestatic int handle_dir(request_rec *r)
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe{
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe dir_config_rec *d =
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe (dir_config_rec *) ap_get_module_config(r->per_dir_config,
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe &dir_module);
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe char *dummy_ptr[1];
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe char **names_ptr;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe int num_names;
fed47023e9be04c612b5f6d4a5ee2b8e7c587181rbowen int error_notfound = 0;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe if (r->uri[0] == '\0' || r->uri[strlen(r->uri) - 1] != '/') {
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe char *ifile;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe if (r->args != NULL)
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe ifile = ap_pstrcat(r->pool, ap_escape_uri(r->pool, r->uri),
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe "/", "?", r->args, NULL);
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe else
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe ifile = ap_pstrcat(r->pool, ap_escape_uri(r->pool, r->uri),
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe "/", NULL);
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe ap_table_setn(r->headers_out, "Location",
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe ap_construct_url(r->pool, ifile, r));
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe return HTTP_MOVED_PERMANENTLY;
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh }
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh /* KLUDGE --- make the sub_req lookups happen in the right directory.
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh * Fixing this in the sub_req_lookup functions themselves is difficult,
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh * and would probably break virtual includes...
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh */
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh if (r->filename[strlen(r->filename) - 1] != '/') {
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh r->filename = ap_pstrcat(r->pool, r->filename, "/", NULL);
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe }
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh if (d->index_names) {
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh names_ptr = (char **)d->index_names->elts;
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh num_names = d->index_names->nelts;
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh }
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh else {
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh dummy_ptr[0] = DEFAULT_INDEX;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe names_ptr = dummy_ptr;
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh num_names = 1;
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh }
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
f039cf01b271a31e317d5b84f24cb135f1c1b6d7nd for (; num_names; ++names_ptr, --num_names) {
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe char *name_ptr = *names_ptr;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe request_rec *rr = ap_sub_req_lookup_uri(name_ptr, r);
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh if (rr->status == HTTP_OK && S_ISREG(rr->finfo.st_mode)) {
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh char *new_uri = ap_escape_uri(r->pool, rr->uri);
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh if (rr->args != NULL)
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh new_uri = ap_pstrcat(r->pool, new_uri, "?", rr->args, NULL);
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh else if (r->args != NULL)
f039cf01b271a31e317d5b84f24cb135f1c1b6d7nd new_uri = ap_pstrcat(r->pool, new_uri, "?", r->args, NULL);
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh
888cb40bdeec5abf452bd85d6bf63b26d5913d4chumbedooh ap_destroy_sub_req(rr);
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe ap_internal_redirect(new_uri, r);
af84459fbf938e508fd10b01cb8d699c79083813takashi return OK;
af84459fbf938e508fd10b01cb8d699c79083813takashi }
2d39a41e98476f5235b7c37ce745a4aa0904b1cbrbowen
fed47023e9be04c612b5f6d4a5ee2b8e7c587181rbowen /* If the request returned a redirect, propagate it to the client */
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe if (ap_is_HTTP_REDIRECT(rr->status) ||
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe (rr->status == HTTP_NOT_ACCEPTABLE && num_names == 1)) {
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe ap_pool_join(r->pool, rr->pool);
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe error_notfound = rr->status;
c8c717fafa0a09ed13469a603a178921b851dd22igalic r->notes = ap_overlay_tables(r->pool, r->notes, rr->notes);
c8c717fafa0a09ed13469a603a178921b851dd22igalic r->headers_out = ap_overlay_tables(r->pool, r->headers_out,
b7f8d802ecaed65eada1fc31472d06d8460d5528igalic rr->headers_out);
b7f8d802ecaed65eada1fc31472d06d8460d5528igalic r->err_headers_out = ap_overlay_tables(r->pool, r->err_headers_out,
b7f8d802ecaed65eada1fc31472d06d8460d5528igalic rr->err_headers_out);
b7f8d802ecaed65eada1fc31472d06d8460d5528igalic return error_notfound;
b7f8d802ecaed65eada1fc31472d06d8460d5528igalic }
b7f8d802ecaed65eada1fc31472d06d8460d5528igalic
b7f8d802ecaed65eada1fc31472d06d8460d5528igalic /* If the request returned something other than 404 (or 200),
b7f8d802ecaed65eada1fc31472d06d8460d5528igalic * it means the module encountered some sort of problem. To be
b7f8d802ecaed65eada1fc31472d06d8460d5528igalic * secure, we should return the error, rather than create
7c7e501f542451bf7225b23cb299ee4228bfe15dgryzor * along a (possibly unsafe) directory index.
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe *
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe * So we store the error, and if none of the listed files
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe * exist, we return the last error response we got, instead
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe * of a directory listing.
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe */
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe if (rr->status && rr->status != HTTP_NOT_FOUND && rr->status != HTTP_OK)
c8c717fafa0a09ed13469a603a178921b851dd22igalic error_notfound = rr->status;
7c7e501f542451bf7225b23cb299ee4228bfe15dgryzor
4bebf996eb7002ebfe897d46a0e0572390604a77nd ap_destroy_sub_req(rr);
4bebf996eb7002ebfe897d46a0e0572390604a77nd }
4bebf996eb7002ebfe897d46a0e0572390604a77nd
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe if (error_notfound)
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe return error_notfound;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe if (r->method_number != M_GET)
8559a67073808d84d85bb5dd552d4247caafe709sf return DECLINED;
8559a67073808d84d85bb5dd552d4247caafe709sf
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe /* nothing for us to do, pass on through */
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe return DECLINED;
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe}
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowestatic const handler_rec dir_handlers[] =
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe{
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe {DIR_MAGIC_TYPE, handle_dir},
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe {NULL}
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe};
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowemodule MODULE_VAR_EXPORT dir_module = {
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe STANDARD20_MODULE_STUFF,
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe create_dir_config, /* create per-directory config structure */
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe merge_dir_configs, /* merge per-directory config structures */
8559a67073808d84d85bb5dd552d4247caafe709sf NULL, /* create per-server config structure */
fed47023e9be04c612b5f6d4a5ee2b8e7c587181rbowen NULL, /* merge per-server config structures */
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe dir_cmds, /* command table */
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe dir_handlers, /* handlers */
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe NULL /* register hooks */
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe};
cd34a6fbf0a2619544a72eadb73f309370bf6682wrowe