diff options
Diffstat (limited to 'src/examples/spdy_fileserver.c')
-rw-r--r-- | src/examples/spdy_fileserver.c | 353 |
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; +} + |