1/*
2    This file is part of libmicrospdy
3    Copyright 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 response_with_callback.c
21 * @brief  shows how to create responses with callbacks
22 * @author Andrey Uzunov
23 */
24
25//for asprintf
26#define _GNU_SOURCE
27
28#include <unistd.h>
29#include <stdlib.h>
30#include <stdint.h>
31#include <stdbool.h>
32#include <string.h>
33#include <stdio.h>
34#include <ctype.h>
35#include <errno.h>
36#include "microspdy.h"
37
38static int run = 1;
39
40
41static ssize_t
42response_callback (void *cls,
43						void *buffer,
44						size_t max,
45						bool *more)
46{
47	FILE *fd =(FILE*)cls;
48
49	int ret = fread(buffer,1,max,fd);
50	*more = feof(fd) == 0;
51
52	if(!(*more))
53		fclose(fd);
54
55	return ret;
56}
57
58
59static void
60response_done_callback(void *cls,
61		       struct SPDY_Response *response,
62		       struct SPDY_Request *request,
63		       enum SPDY_RESPONSE_RESULT status,
64		       bool streamopened)
65{
66	(void)streamopened;
67	(void)status;
68
69	printf("answer for %s was sent\n", (char *)cls);
70
71	SPDY_destroy_request(request);
72	SPDY_destroy_response(response);
73	free(cls);
74}
75
76
77static void
78standard_request_handler(void *cls,
79						struct SPDY_Request * request,
80						uint8_t priority,
81                        const char *method,
82                        const char *path,
83                        const char *version,
84                        const char *host,
85                        const char *scheme,
86						struct SPDY_NameValue * headers,
87            bool more)
88{
89	(void)cls;
90	(void)request;
91	(void)priority;
92	(void)host;
93	(void)scheme;
94	(void)headers;
95	(void)more;
96
97	char *html;
98	struct SPDY_Response *response=NULL;
99	struct SPDY_NameValue *resp_headers;
100
101	printf("received request for '%s %s %s'\n", method, path, version);
102	if(strcmp(path,"/spdy-draft.txt")==0)
103	{
104		FILE *fd = fopen(DATA_DIR "spdy-draft.txt","r");
105
106		if(NULL == (resp_headers = SPDY_name_value_create()))
107		{
108			fprintf(stdout,"SPDY_name_value_create failed\n");
109			abort();
110		}
111		if(SPDY_YES != SPDY_name_value_add(resp_headers,SPDY_HTTP_HEADER_CONTENT_TYPE,"text/plain"))
112		{
113			fprintf(stdout,"SPDY_name_value_add failed\n");
114			abort();
115		}
116
117		response = SPDY_build_response_with_callback(200,NULL,
118			SPDY_HTTP_VERSION_1_1,resp_headers,&response_callback,fd,SPDY_MAX_SUPPORTED_FRAME_SIZE);
119		SPDY_name_value_destroy(resp_headers);
120	}
121	else
122	{
123		if(strcmp(path,"/close")==0)
124		{
125			asprintf(&html,"<html>"
126		"<body><b>Closing now!</body></html>");
127			run = 0;
128		}
129		else
130		{
131			asprintf(&html,"<html>"
132		"<body><a href=\"/spdy-draft.txt\">/spdy-draft.txt</a><br></body></html>");
133		}
134
135		response = SPDY_build_response(200,NULL,SPDY_HTTP_VERSION_1_1,NULL,html,strlen(html));
136		free(html);
137	}
138
139	if(NULL==response){
140		fprintf(stdout,"no response obj\n");
141		abort();
142	}
143
144	void *clspath = strdup(path);
145
146	if(SPDY_queue_response(request,response,true,false,&response_done_callback,clspath)!=SPDY_YES)
147	{
148		fprintf(stdout,"queue\n");
149		abort();
150	}
151}
152
153
154int
155main (int argc, char *const *argv)
156{
157	unsigned long long timeoutlong=0;
158	struct timeval timeout;
159	int ret;
160	fd_set read_fd_set;
161	fd_set write_fd_set;
162	fd_set except_fd_set;
163	int maxfd = -1;
164	struct SPDY_Daemon *daemon;
165
166	if(argc != 2)
167	{
168		return 1;
169	}
170
171	SPDY_init();
172
173	daemon = SPDY_start_daemon(atoi(argv[1]),
174								DATA_DIR "cert-and-key.pem",
175								DATA_DIR "cert-and-key.pem",
176								NULL,
177								NULL,
178								&standard_request_handler,
179								NULL,
180								NULL,
181								SPDY_DAEMON_OPTION_SESSION_TIMEOUT,
182								1800,
183								SPDY_DAEMON_OPTION_END);
184
185	if(NULL==daemon){
186		printf("no daemon\n");
187		return 1;
188	}
189
190	do
191	{
192		FD_ZERO(&read_fd_set);
193		FD_ZERO(&write_fd_set);
194		FD_ZERO(&except_fd_set);
195
196		ret = SPDY_get_timeout(daemon, &timeoutlong);
197		if(SPDY_NO == ret || timeoutlong > 1000)
198		{
199			timeout.tv_sec = 1;
200      timeout.tv_usec = 0;
201		}
202		else
203		{
204			timeout.tv_sec = timeoutlong / 1000;
205			timeout.tv_usec = (timeoutlong % 1000) * 1000;
206		}
207
208		maxfd = SPDY_get_fdset (daemon,
209								&read_fd_set,
210								&write_fd_set,
211								&except_fd_set);
212
213		ret = select(maxfd+1, &read_fd_set, &write_fd_set, &except_fd_set, &timeout);
214
215		switch(ret) {
216			case -1:
217				printf("select error: %i\n", errno);
218				break;
219			case 0:
220
221				break;
222			default:
223				SPDY_run(daemon);
224
225			break;
226		}
227	}
228	while(run);
229
230	SPDY_stop_daemon(daemon);
231
232	SPDY_deinit();
233
234	return 0;
235}
236
237