root/cherokee/trunk/cherokee/handler_nn.c

Revision 1131, 4.4 kB (checked in by alo, 3 months ago)

--

Line 
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* Cherokee
4  *
5  * Authors:
6  *      Alvaro Lopez Ortega <alvaro@alobbs.com>
7  *
8  * Copyright (C) 2001-2008 Alvaro Lopez Ortega
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of version 2 of the GNU General Public
12  * License as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22  * USA
23  */
24
25 #include "common-internal.h"
26 #include "handler_nn.h"
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <dirent.h>
32
33 #include "thread.h"
34 #include "connection.h"
35 #include "connection-protected.h"
36 #include "module.h"
37 #include "plugin_loader.h"
38 #include "connection.h"
39 #include "handler_common.h"
40 #include "handler_redir.h"
41 #include "levenshtein_distance.h"
42
43
44 ret_t
45 cherokee_handler_nn_configure (cherokee_config_node_t *conf, cherokee_server_t *srv, cherokee_module_props_t **_props)
46 {
47         return cherokee_handler_common_configure (conf, srv, _props);
48 }
49
50
51 static ret_t
52 get_nearest_from_directory (char *directory, char *request, cherokee_buffer_t *output)
53 {
54         DIR               *dir;
55         struct dirent     *entry;
56         int                min_diff = 9999;
57         cherokee_boolean_t found    = false;
58
59         dir = opendir(directory);
60         if (dir == NULL)
61                 goto go_out;
62
63         while ((entry = readdir (dir)) != NULL) {
64                 int dis;
65                          
66                 if (!strncmp (entry->d_name, ".", 1)) continue;
67                 if (!strncmp (entry->d_name, "..",2)) continue;
68
69                 dis = distance ((char *)request, entry->d_name);
70                 if (dis < min_diff) {
71                         min_diff = dis;
72                         found    = true;
73                        
74                         cherokee_buffer_clean (output);
75                         cherokee_buffer_add (output, entry->d_name, strlen(entry->d_name));
76                 }
77                          
78         }
79         closedir (dir);
80
81 go_out:
82         return (found) ? ret_ok : ret_error;
83 }
84
85
86 static ret_t
87 get_nearest_name (
88                         cherokee_connection_t *conn,
89                         cherokee_buffer_t *local_dir,
90                         cherokee_buffer_t *request,
91                         cherokee_buffer_t *output)
92 {
93         char              *rest;
94         ret_t              ret = ret_ok;
95         cherokee_thread_t *thread = CONN_THREAD(conn);
96         cherokee_buffer_t *req = THREAD_TMP_BUF1(thread);/* Request w/o last word */
97
98         /* Build the local request path
99          */
100         rest = strrchr (request->buf, '/');
101         if (rest == NULL) {
102                 return ret_error;
103         }
104         rest++;
105
106         cherokee_buffer_clean (req);
107         cherokee_buffer_add_buffer (req, local_dir);
108         cherokee_buffer_add (req, request->buf, rest - request->buf);
109        
110         /* Copy the new filename to the output buffer
111          */
112         ret = get_nearest_from_directory (req->buf, rest, output);
113
114         if (unlikely (ret != ret_ok)) {
115                 return ret_error;
116         }
117
118         /* Prepend the rest of the old request to the new filename
119          */
120         cherokee_buffer_prepend (output, request->buf, rest - request->buf);
121         return ret_ok;
122 }
123
124
125 ret_t
126 cherokee_handler_nn_new (cherokee_handler_t **hdl, void *cnt, cherokee_module_props_t *props)
127 {
128         ret_t                  ret;
129         struct stat            info;
130         int                    stat_ret;
131         cherokee_connection_t *conn   = CONN(cnt);
132
133         cherokee_buffer_add (&conn->local_directory, conn->request.buf, conn->request.len);
134         stat_ret = stat (conn->local_directory.buf, &info);
135         cherokee_buffer_drop_endding (&conn->local_directory, conn->request.len);
136        
137         /* Maybe the file/dir exists
138          */
139         if (stat_ret == 0) {
140                 return cherokee_handler_common_new (hdl, cnt, props);
141         }
142
143         /* It doesn't exists, let's redirect it..
144          */
145         cherokee_buffer_clean (&conn->redirect);
146
147         ret = get_nearest_name (conn, &conn->local_directory, &conn->request, &conn->redirect);
148         if (unlikely (ret != ret_ok)) {
149                 conn->error_code = http_not_found;
150                 return ret_error;
151         }
152
153         cherokee_buffer_swap_buffers (&conn->request, &conn->redirect);
154         cherokee_buffer_clean (&conn->redirect);
155
156         return ret_eagain;
157 }
158
159
160 /*   Library init function
161  */
162 static cherokee_boolean_t _nn_is_init = false;
163
164 void
165 PLUGIN_INIT_NAME(nn) (cherokee_plugin_loader_t *loader)
166 {
167         /* Is init?
168          */
169         if (_nn_is_init)
170                 return;
171         _nn_is_init = true;
172            
173         /* Load the dependences
174          */
175         cherokee_plugin_loader_load (loader, "common");
176 }
177
178 PLUGIN_INFO_HANDLER_EASY_INIT (nn, http_all_methods);
179
Note: See TracBrowser for help on using the browser.