lots of stuff, some works - some not.
[krsd] / src / handler / dispatch.c
1 /*
2  * rs-serve - (c) 2013 Niklas E. Cathor
3  *
4  * This program is distributed in the hope that it will be useful,
5  * but WITHOUT ANY WARRANTY; without even the implied warranty of
6  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7  * GNU Affero General Public License for more details.
8  *
9  * You should have received a copy of the GNU Affero General Public License
10  * along with this program. If not, see <http://www.gnu.org/licenses/>.
11  */
12
13 #include "rs-serve.h"
14
15 void start_storage_process(uid_t uid, int initial_fd, char *initial_buf, int initial_buf_len) {
16   struct rs_process_info *storage_process = malloc(sizeof(struct rs_process_info));
17   if(storage_process == NULL) {
18     log_error("malloc() failed: %s", strerror(errno));
19     return;
20   }
21   storage_process->uid = uid;
22   if(start_process(storage_process, storage_main,
23                    initial_fd, initial_buf, initial_buf_len) != 0) {
24     free(storage_process);
25     return;
26   }
27 }
28
29 static char *my_strtok(char *string, char *delim, char **saveptr) {
30   char *ptr = string ? string : *saveptr, *dp;
31   char *start = ptr;
32   if(*delim == 0) { // empty delimiter => return entire string.
33     log_debug("returning start: %s", start);
34     return start;
35   }
36   for(;*ptr != 0; ptr++) {
37     for(dp = delim; *dp != 0; dp++) {
38       if(*ptr == *dp) {
39         if(*ptr == '\n') {
40           log_debug("found newline, previous char is: %d (%d)", *(ptr - 1), '\r');
41         }
42         *ptr++ = 0;
43         *saveptr = ptr;
44         return start;
45       }
46     }
47   }
48   return NULL;
49 }
50
51 int dispatch_request(struct evbuffer *buffer, int fd) {
52   size_t buf_len = evbuffer_get_length(buffer);
53   char *buf = malloc(buf_len + 1);
54   if(buf == NULL) {
55     log_error("malloc() failed: %s", strerror(errno));
56     return -1;
57   }
58   evbuffer_remove(buffer, buf, buf_len);
59   buf[buf_len] = 0; // terminate string.
60
61   // parse everything
62
63   log_debug("Got data buf (%d): %s", buf_len, buf);
64
65   char *saveptr;
66   char *verb = my_strtok(buf, " ", &saveptr);
67   saveptr++; // skip initial slash
68   char *username = my_strtok(NULL, "/ ", &saveptr);
69   char *file_path = my_strtok(NULL, " ", &saveptr);
70   char *http_version = my_strtok(NULL, "\r", &saveptr);
71   saveptr++; // skip \n
72   char *rest = my_strtok(NULL, "", &saveptr);
73
74   log_debug("verb: %s\nusername: %s\nfile_path: %s\nhttp_version: %s\nrest: %s", verb, username, file_path, http_version, rest);
75   if(verb == NULL || username == NULL || file_path == NULL ||
76      http_version == NULL) {
77     //log_debug("verb: %s, username: %s, file_path: %s, http_version: %s, rest: %s", verb, username, file_path, http_version);
78     return -1;
79   }
80
81   if(strncmp(http_version, "HTTP/1.", 7) != 0) {
82     log_error("Invalid request (HTTP version specified as \"%s\")", http_version);
83     return -1;
84   }
85
86   /* log_debug("Parsed something. Let's see:\n  verb: %s\n  username: %s\n  path: %s\n  http version: %s\n  rest: %s", */
87   /*           verb, username, file_path, http_version, rest); */
88
89   uid_t uid = user_get_uid(username);
90
91   if(uid == -1) {
92     // TODO: send 404 response here
93     log_error("User not found: %s", username);
94     free(buf);
95     return -1;
96   } else if(uid == -2) {
97     // TODO: send 500 response here
98     log_error("Failed to get uid for user: %s", username);
99     free(buf);
100     return -1;
101   }
102
103   // TODO: add check for UID > MIN_UID
104   //   (we don't want to fork storage workers for system users)
105
106   // rewrite first line to only include file path
107
108   int new_len = sprintf(buf, "%s /%s %s\r\n%s", verb, file_path, http_version, rest);
109   log_debug("reallocating to %d bytes", new_len + 1);
110   buf = realloc(buf, new_len + 1);
111   if(buf == NULL) {
112     log_error("BUG: realloc() failed to shrink buffer from %d to %d bytes: %s",
113               buf_len + 1, new_len + 1, strerror(errno));
114   }
115   buf_len = new_len;
116
117   struct rs_process_info *storage_process = process_find_uid(uid);
118   if(storage_process == NULL) {
119     start_storage_process(uid, fd, buf, buf_len + 1);
120   } else {
121     send_fd_to_process(storage_process, fd, buf, buf_len + 1);
122   }
123
124   free(buf);
125
126   return 0;
127 }