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.c353
1 files changed, 353 insertions, 0 deletions
diff --git a/src/examples/spdy_fileserver.c b/src/examples/spdy_fileserver.c
new file mode 100644
index 00000000..0a0254ff
--- /dev/null
+++ b/src/examples/spdy_fileserver.c
@@ -0,0 +1,353 @@
+/*
+ This file is part of libmicrospdy
+ Copyright Copyright (C) 2013 Andrey Uzunov
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file fileserver.c
+ * @brief Simple example how the lib can be used for serving
+ * files directly read from the system
+ * @author Andrey Uzunov
+ */
+
+//for asprintf
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include "microspdy.h"
+#include "time.h"
+
+
+int run = 1;
+char* basedir;
+
+
+#define GET_MIME_TYPE(fname, mime) do {\
+ unsigned int __len = strlen(fname);\
+ if (__len < 4 || '.' != (fname)[__len - 4]) \
+ { \
+ (mime) = strdup("application/octet-stream");\
+ printf("MIME for %s is applic...\n", (fname));\
+ }\
+ else {\
+ const char * __ext = &(fname)[__len - 3];\
+ if(0 == strcmp(__ext, "jpg")) (mime) = strdup("image/jpeg");\
+ else if(0 == strcmp(__ext, "png")) (mime) = strdup("image/png");\
+ else if(0 == strcmp(__ext, "css")) (mime) = strdup("text/css");\
+ else if(0 == strcmp(__ext, "gif")) (mime) = strdup("image/gif");\
+ else if(0 == strcmp(__ext, "htm")) (mime) = strdup("text/html");\
+ else \
+ { \
+ (mime) = strdup("application/octet-stream");\
+ printf("MIME for %s is applic...\n", (fname));\
+ }\
+ }\
+ if(NULL == (mime))\
+ {\
+ printf("no memory\n");\
+ abort();\
+ }\
+ } while (0)
+
+
+static const char *DAY_NAMES[] =
+ { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+
+static const char *MONTH_NAMES[] =
+ { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+//taken from http://stackoverflow.com/questions/2726975/how-can-i-generate-an-rfc1123-date-string-from-c-code-win32
+//and modified for linux
+char *Rfc1123_DateTimeNow()
+{
+ const int RFC1123_TIME_LEN = 29;
+ time_t t;
+ struct tm tm;
+ char * buf = malloc(RFC1123_TIME_LEN+1);
+
+ if (NULL == buf)
+ return NULL;
+ time(&t);
+ gmtime_r( &t, &tm);
+
+ strftime(buf, RFC1123_TIME_LEN+1, "---, %d --- %Y %H:%M:%S GMT", &tm);
+ memcpy(buf, DAY_NAMES[tm.tm_wday], 3);
+ memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3);
+
+ return buf;
+}
+
+
+ssize_t
+response_callback (void *cls,
+ void *buffer,
+ size_t max,
+ bool *more)
+{
+ FILE *fd =(FILE*)cls;
+
+ int ret = fread(buffer,1,max,fd);
+ *more = feof(fd) == 0;
+
+ //if(!(*more))
+ // fclose(fd);
+
+ return ret;
+}
+
+
+void
+response_done_callback(void *cls,
+ struct SPDY_Response *response,
+ struct SPDY_Request *request,
+ enum SPDY_RESPONSE_RESULT status,
+ bool streamopened)
+{
+ (void)streamopened;
+ (void)status;
+ //printf("answer for %s was sent\n", (char *)cls);
+
+ /*if(SPDY_RESPONSE_RESULT_SUCCESS != status)
+ {
+ printf("answer for %s was NOT sent, %i\n", (char *)cls,status);
+ }*/
+
+ SPDY_destroy_request(request);
+ SPDY_destroy_response(response);
+ if(NULL!=cls)fclose(cls);
+}
+
+void
+standard_request_handler(void *cls,
+ struct SPDY_Request * request,
+ uint8_t priority,
+ const char *method,
+ const char *path,
+ const char *version,
+ const char *host,
+ const char *scheme,
+ struct SPDY_NameValue * headers,
+ bool more)
+{
+ (void)cls;
+ (void)request;
+ (void)priority;
+ (void)host;
+ (void)scheme;
+ (void)headers;
+ (void)method;
+ (void)version;
+ (void)more;
+
+ struct SPDY_Response *response=NULL;
+ struct SPDY_NameValue *resp_headers;
+ char *fname;
+ char *fsize;
+ char *mime=NULL;
+ char *date=NULL;
+ ssize_t filesize = -666;
+ FILE *fd = NULL;
+ int ret = -666;
+
+ //printf("received request for '%s %s %s'\n", method, path, version);
+ if(strlen(path) > 1 && NULL == strstr(path, "..") && '/' == path[0])
+ {
+ asprintf(&fname,"%s%s",basedir,path);
+ if(0 == access(fname, R_OK))
+ {
+ if(NULL == (fd = fopen(fname,"r"))
+ || 0 != (ret = fseek(fd, 0L, SEEK_END))
+ || -1 == (filesize = ftell(fd))
+ || 0 != (ret = fseek(fd, 0L, SEEK_SET)))
+ {
+ printf("Error on opening %s\n%p %i %zd\n",fname, fd, ret, filesize);
+ response = SPDY_build_response(SPDY_HTTP_INTERNAL_SERVER_ERROR,NULL,SPDY_HTTP_VERSION_1_1,NULL,NULL,0);
+ }
+ else
+ {
+ if(NULL == (resp_headers = SPDY_name_value_create()))
+ {
+ printf("SPDY_name_value_create failed\n");
+ abort();
+ }
+
+ date = Rfc1123_DateTimeNow();
+ if(NULL == date
+ || SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_DATE,date))
+ {
+ printf("SPDY_name_value_add or Rfc1123_DateTimeNow failed\n");
+ abort();
+ }
+ free(date);
+
+ if(-1 == asprintf(&fsize, "%zd", filesize)
+ || SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_LENGTH,fsize))
+ {
+ printf("SPDY_name_value_add or asprintf failed\n");
+ abort();
+ }
+ free(fsize);
+
+ GET_MIME_TYPE(path,mime);
+ if(SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_TYPE,mime))
+ {
+ printf("SPDY_name_value_add failed\n");
+ abort();
+ }
+ free(mime);
+
+ if(SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_SERVER,"libmicrospdy/fileserver"))
+ {
+ printf("SPDY_name_value_add failed\n");
+ abort();
+ }
+
+ response = SPDY_build_response_with_callback(200,NULL,
+ SPDY_HTTP_VERSION_1_1,resp_headers,&response_callback,fd,SPDY_MAX_SUPPORTED_FRAME_SIZE);
+ SPDY_name_value_destroy(resp_headers);
+ }
+
+ if(NULL==response){
+ printf("no response obj\n");
+ abort();
+ }
+
+ if(SPDY_queue_response(request,response,true,false,&response_done_callback,fd)!=SPDY_YES)
+ {
+ printf("queue\n");
+ abort();
+ }
+
+ free(fname);
+ return;
+ }
+ free(fname);
+ }
+
+ if(strcmp(path,"/close")==0)
+ {
+ run = 0;
+ }
+
+ response = SPDY_build_response(SPDY_HTTP_NOT_FOUND,NULL,SPDY_HTTP_VERSION_1_1,NULL,NULL,0);
+ printf("Not found %s\n",path);
+
+ if(NULL==response){
+ printf("no response obj\n");
+ abort();
+ }
+
+ if(SPDY_queue_response(request,response,true,false,&response_done_callback,NULL)!=SPDY_YES)
+ {
+ printf("queue\n");
+ abort();
+ }
+}
+
+int
+main (int argc, char *const *argv)
+{
+ unsigned long long timeoutlong=0;
+ struct timeval timeout;
+ int ret;
+ fd_set read_fd_set;
+ fd_set write_fd_set;
+ fd_set except_fd_set;
+ int maxfd = -1;
+ struct SPDY_Daemon *daemon;
+
+ if(argc != 5)
+ {
+ printf("Usage: %s cert-file key-file base-dir port\n", argv[0]);
+ return 1;
+ }
+
+ SPDY_init();
+
+ daemon = SPDY_start_daemon(atoi(argv[4]),
+ argv[1],
+ argv[2],
+ NULL,
+ NULL,
+ &standard_request_handler,
+ NULL,
+ NULL,
+ SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
+ 1800,
+ SPDY_DAEMON_OPTION_END);
+
+ if(NULL==daemon){
+ printf("no daemon\n");
+ return 1;
+ }
+
+ basedir = argv[3];
+
+ do
+ {
+ FD_ZERO(&read_fd_set);
+ FD_ZERO(&write_fd_set);
+ FD_ZERO(&except_fd_set);
+
+ ret = SPDY_get_timeout(daemon, &timeoutlong);
+ if(SPDY_NO == ret || timeoutlong > 1000)
+ {
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+ }
+ else
+ {
+ timeout.tv_sec = timeoutlong / 1000;
+ timeout.tv_usec = (timeoutlong % 1000) * 1000;
+ }
+
+ maxfd = SPDY_get_fdset (daemon,
+ &read_fd_set,
+ &write_fd_set,
+ &except_fd_set);
+
+ ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
+
+ switch(ret) {
+ case -1:
+ printf("select error: %i\n", errno);
+ break;
+ case 0:
+
+ break;
+ default:
+ SPDY_run(daemon);
+
+ break;
+ }
+ }
+ while(run);
+
+ SPDY_stop_daemon(daemon);
+
+ SPDY_deinit();
+
+ return 0;
+}
+