aboutsummaryrefslogtreecommitdiff
path: root/src/examples/spdy_fileserver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/examples/spdy_fileserver.c')
-rw-r--r--src/examples/spdy_fileserver.c340
1 files changed, 340 insertions, 0 deletions
diff --git a/src/examples/spdy_fileserver.c b/src/examples/spdy_fileserver.c
new file mode 100644
index 00000000..a59b6e9e
--- /dev/null
+++ b/src/examples/spdy_fileserver.c
@@ -0,0 +1,340 @@
1/*
2 This file is part of libmicrospdy
3 Copyright (C) 2013 Andrey Uzunov
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file fileserver.c
21 * @brief Simple example how the lib can be used for serving
22 * files directly read from the system
23 * @author Andrey Uzunov
24 */
25
26#include <unistd.h>
27#include <stdlib.h>
28#include <stdint.h>
29#include <stdbool.h>
30#include <string.h>
31#include <stdio.h>
32#include <ctype.h>
33#include <errno.h>
34#include "microspdy.h"
35#include "time.h"
36
37
38int run = 1;
39char* basedir;
40
41
42#define GET_MIME_TYPE(fname, mime) do {\
43 uint __len = strlen(fname);\
44 if (__len < 4 || '.' != (fname)[__len - 4]) break;\
45 const char * __ext = &(fname)[__len - 3];\
46 if(0 == strcmp(__ext, "jpg")) (mime) = strdup("image/jpeg");\
47 else if(0 == strcmp(__ext, "png")) (mime) = strdup("image/png");\
48 else if(0 == strcmp(__ext, "css")) (mime) = strdup("text/css");\
49 else if(0 == strcmp(__ext, "gif")) (mime) = strdup("image/gif");\
50 else if(0 == strcmp(__ext, "htm")) (mime) = strdup("text/html");\
51 else \
52 { \
53 (mime) = strdup("application/octet-stream");\
54 printf("MIME for %s is applic...\n", (fname));\
55 }\
56 if(NULL == (mime))\
57 {\
58 printf("no memory\n");\
59 abort();\
60 }\
61 } while (0)
62
63
64static const char *DAY_NAMES[] =
65 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
66
67static const char *MONTH_NAMES[] =
68 { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
69 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
70
71//taken from http://stackoverflow.com/questions/2726975/how-can-i-generate-an-rfc1123-date-string-from-c-code-win32
72//and modified for linux
73char *Rfc1123_DateTimeNow()
74{
75 const int RFC1123_TIME_LEN = 29;
76 time_t t;
77 struct tm tm;
78 char * buf = malloc(RFC1123_TIME_LEN+1);
79
80 time(&t);
81 gmtime_r( &t, &tm);
82
83 strftime(buf, RFC1123_TIME_LEN+1, "---, %d --- %Y %H:%M:%S GMT", &tm);
84 memcpy(buf, DAY_NAMES[tm.tm_wday], 3);
85 memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3);
86
87 return buf;
88}
89
90
91ssize_t
92response_callback (void *cls,
93 void *buffer,
94 size_t max,
95 bool *more)
96{
97 FILE *fd =(FILE*)cls;
98
99 int ret = fread(buffer,1,max,fd);
100 *more = feof(fd) == 0;
101
102 //if(!(*more))
103 // fclose(fd);
104
105 return ret;
106}
107
108
109void
110response_done_callback(void *cls,
111 struct SPDY_Response *response,
112 struct SPDY_Request *request,
113 enum SPDY_RESPONSE_RESULT status,
114 bool streamopened)
115{
116 (void)streamopened;
117 //printf("answer for %s was sent\n", (char *)cls);
118
119 /*if(SPDY_RESPONSE_RESULT_SUCCESS != status)
120 {
121 printf("answer for %s was NOT sent, %i\n", (char *)cls,status);
122 }*/
123
124 SPDY_destroy_request(request);
125 SPDY_destroy_response(response);
126 if(NULL!=cls)fclose(cls);
127}
128
129void
130standard_request_handler(void *cls,
131 struct SPDY_Request * request,
132 uint8_t priority,
133 const char *method,
134 const char *path,
135 const char *version,
136 const char *host,
137 const char *scheme,
138 struct SPDY_NameValue * headers)
139{
140 (void)cls;
141 (void)request;
142 (void)priority;
143 (void)host;
144 (void)scheme;
145 (void)headers;
146
147 struct SPDY_Response *response=NULL;
148 struct SPDY_NameValue *resp_headers;
149 char *fname;
150 char *fsize;
151 char *mime=NULL;
152 char *date=NULL;
153 ssize_t filesize = -666;
154 FILE *fd = NULL;
155 int ret = -666;
156
157 //printf("received request for '%s %s %s'\n", method, path, version);
158 if(strlen(path) > 1 && NULL == strstr(path, "..") && '/' == path[0])
159 {
160 asprintf(&fname,"%s%s",basedir,path);
161 if(0 == access(fname, R_OK))
162 {
163 if(NULL == (fd = fopen(fname,"r"))
164 || 0 != (ret = fseek(fd, 0L, SEEK_END))
165 || -1 == (filesize = ftell(fd))
166 || 0 != (ret = fseek(fd, 0L, SEEK_SET)))
167 {
168 printf("Error on opening %s\n%i %i %i\n",fname, fd, ret, filesize);
169 response = SPDY_build_response(SPDY_HTTP_INTERNAL_SERVER_ERROR,NULL,SPDY_HTTP_VERSION_1_1,NULL,NULL,0);
170 }
171 else
172 {
173 if(NULL == (resp_headers = SPDY_name_value_create()))
174 {
175 printf("SPDY_name_value_create failed\n");
176 abort();
177 }
178
179 date = Rfc1123_DateTimeNow();
180 if(NULL == date
181 || SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_DATE,date))
182 {
183 printf("SPDY_name_value_add or Rfc1123_DateTimeNow failed\n");
184 abort();
185 }
186 free(date);
187
188 if(-1 == asprintf(&fsize, "%i", filesize)
189 || SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_LENGTH,fsize))
190 {
191 printf("SPDY_name_value_add or asprintf failed\n");
192 abort();
193 }
194 free(fsize);
195
196 GET_MIME_TYPE(path,mime);
197 if(SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_TYPE,mime))
198 {
199 printf("SPDY_name_value_add failed\n");
200 abort();
201 }
202 free(mime);
203
204 if(SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_SERVER,"libmicrospdy/fileserver"))
205 {
206 printf("SPDY_name_value_add failed\n");
207 abort();
208 }
209
210 response = SPDY_build_response_with_callback(200,NULL,
211 SPDY_HTTP_VERSION_1_1,resp_headers,&response_callback,fd,SPDY_MAX_SUPPORTED_FRAME_SIZE);
212 SPDY_name_value_destroy(resp_headers);
213 }
214
215 if(NULL==response){
216 printf("no response obj\n");
217 abort();
218 }
219
220 if(SPDY_queue_response(request,response,true,false,&response_done_callback,fd)!=SPDY_YES)
221 {
222 printf("queue\n");
223 abort();
224 }
225
226 free(fname);
227 return;
228 }
229 free(fname);
230 }
231
232 if(strcmp(path,"/close")==0)
233 {
234 run = 0;
235 }
236
237 response = SPDY_build_response(SPDY_HTTP_NOT_FOUND,NULL,SPDY_HTTP_VERSION_1_1,NULL,NULL,0);
238 printf("Not found %s\n",path);
239
240 if(NULL==response){
241 printf("no response obj\n");
242 abort();
243 }
244
245 if(SPDY_queue_response(request,response,true,false,&response_done_callback,NULL)!=SPDY_YES)
246 {
247 printf("queue\n");
248 abort();
249 }
250}
251
252int
253main (int argc, char *const *argv)
254{
255 unsigned long long timeoutlong=0;
256 struct timeval timeout;
257 int ret;
258 fd_set read_fd_set;
259 fd_set write_fd_set;
260 fd_set except_fd_set;
261 int maxfd = -1;
262 struct SPDY_Daemon *daemon;
263
264 if(argc != 5)
265 {
266 printf("Usage: %s cert-file key-file base-dir port\n", argv[0]);
267 return 1;
268 }
269
270 SPDY_init();
271
272 daemon = SPDY_start_daemon(atoi(argv[4]),
273 argv[1],
274 argv[2],
275 NULL,
276 NULL,
277 &standard_request_handler,
278 NULL,
279 NULL,
280 SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
281 1800,
282 SPDY_DAEMON_OPTION_END);
283
284 if(NULL==daemon){
285 printf("no daemon\n");
286 return 1;
287 }
288
289 basedir = argv[3];
290 timeout.tv_usec = 0;
291
292 do
293 {
294 FD_ZERO(&read_fd_set);
295 FD_ZERO(&write_fd_set);
296 FD_ZERO(&except_fd_set);
297
298 ret = SPDY_get_timeout(daemon, &timeoutlong);
299 if(SPDY_NO == ret || timeoutlong > 1)
300 {
301 //do sth else
302 //sleep(1);
303
304 //try new connection
305 timeout.tv_sec = 1;
306 }
307 else
308 {
309 timeout.tv_sec = timeoutlong;
310 }
311
312 maxfd = SPDY_get_fdset (daemon,
313 &read_fd_set,
314 &write_fd_set,
315 &except_fd_set);
316
317 ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
318
319 switch(ret) {
320 case -1:
321 printf("select error: %i\n", errno);
322 break;
323 case 0:
324
325 break;
326 default:
327 SPDY_run(daemon);
328
329 break;
330 }
331 }
332 while(run);
333
334 SPDY_stop_daemon(daemon);
335
336 SPDY_deinit();
337
338 return 0;
339}
340