1/*
2    This file is part of libmicrospdy
3    Copyright Copyright (C) 2012 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 applicationlayer.c
21 * @brief  SPDY application or HTTP layer
22 * @author Andrey Uzunov
23 */
24
25#include "platform.h"
26#include "applicationlayer.h"
27#include "alstructures.h"
28#include "structures.h"
29#include "internal.h"
30#include "daemon.h"
31#include "session.h"
32
33
34void
35spdy_callback_response_done(void *cls,
36						struct SPDY_Response *response,
37						struct SPDY_Request *request,
38						enum SPDY_RESPONSE_RESULT status,
39						bool streamopened)
40{
41	(void)cls;
42	(void)status;
43	(void)streamopened;
44
45	SPDY_destroy_request(request);
46	SPDY_destroy_response(response);
47}
48
49
50/**
51 * Callback called when new stream is created. It extracts the info from
52 * the stream to create (HTTP) request object and pass it to the client.
53 *
54 * @param cls
55 * @param stream the new SPDY stream
56 * @return SPDY_YES on success, SPDY_NO on memomry error
57 */
58static int
59spdy_handler_new_stream (void *cls,
60						struct SPDYF_Stream * stream)
61{
62	(void)cls;
63	unsigned int i;
64	char *method = NULL;
65	char *path = NULL;
66	char *version = NULL;
67	char *host = NULL;
68	char *scheme = NULL;
69	struct SPDY_Request * request = NULL;
70	struct SPDY_NameValue * headers = NULL;
71	struct SPDY_NameValue * iterator = stream->headers;
72	struct SPDY_Daemon *daemon;
73
74	daemon = stream->session->daemon;
75
76	//if the user doesn't care, ignore it
77	if(NULL == daemon->new_request_cb)
78		return SPDY_YES;
79
80	if(NULL == (headers=SPDY_name_value_create()))
81		goto free_and_fail;
82
83	if(NULL==(request = malloc(sizeof(struct SPDY_Request))))
84		goto free_and_fail;
85
86	memset(request, 0, sizeof(struct SPDY_Request));
87	request->stream = stream;
88
89	/* extract the mandatory fields from stream->headers' structure
90	 * to pass them to the client */
91	while(iterator != NULL)
92	{
93		if(strcmp(":method",iterator->name) == 0)
94		{
95			if(1 != iterator->num_values)
96				break;
97			method = iterator->value[0];
98		}
99		else if(strcmp(":path",iterator->name) == 0)
100		{
101			if(1 != iterator->num_values)
102				break;
103			path = iterator->value[0];
104		}
105		else if(strcmp(":version",iterator->name) == 0)
106		{
107			if(1 != iterator->num_values)
108				break;
109			version = iterator->value[0];
110		}
111		else if(strcmp(":host",iterator->name) == 0)
112		{
113			//TODO can it have more values?
114			if(1 != iterator->num_values)
115				break;
116			host = iterator->value[0];
117		}
118		else if(strcmp(":scheme",iterator->name) == 0)
119		{
120			if(1 != iterator->num_values)
121				break;
122			scheme = iterator->value[0];
123		}
124		else
125			for(i=0; i<iterator->num_values; ++i)
126				if (SPDY_YES != SPDY_name_value_add(headers,iterator->name,iterator->value[i]))
127        {
128          SPDY_destroy_request(request);
129					goto free_and_fail;
130        }
131
132		iterator = iterator->next;
133	}
134
135	request->method=method;
136  request->path=path;
137  request->version=version;
138  request->host=host;
139  request->scheme=scheme;
140  request->headers=headers;
141
142	//check request validity, all these fields are mandatory for a request
143	if(NULL == method || strlen(method) == 0
144		|| NULL == path || strlen(path) == 0
145		|| NULL == version || strlen(version) == 0
146		|| NULL == host || strlen(host) == 0
147		|| NULL == scheme || strlen(scheme) == 0
148		)
149	{
150		//TODO HTTP 400 Bad Request must be answered
151
152		SPDYF_DEBUG("Bad request");
153
154		SPDY_destroy_request(request);
155
156		return SPDY_YES;
157	}
158
159	//call client's callback function to notify
160	daemon->new_request_cb(daemon->cls,
161						request,
162						stream->priority,
163                        method,
164                        path,
165                        version,
166                        host,
167                        scheme,
168						headers,
169            !stream->is_in_closed);
170
171  stream->cls = request;
172
173	return SPDY_YES;
174
175	//for GOTO
176	free_and_fail:
177
178	SPDY_name_value_destroy(headers);
179	return SPDY_NO;
180}
181
182
183/**
184 * TODO
185 */
186static int
187spdy_handler_new_data (void * cls,
188					 struct SPDYF_Stream *stream,
189					 const void * buf,
190					 size_t size,
191					 bool more)
192{
193  return stream->session->daemon->received_data_cb(cls, stream->cls, buf, size, more);
194}
195
196
197
198/**
199 * Callback to be called when the response queue object was handled and
200 * the data was already sent or discarded.
201 *
202 * @param cls
203 * @param response_queue the object which is being handled
204 * @param status shows if actually the response was sent or it was
205 * 			discarded by the lib for any reason (e.g., closing session,
206 * 			closing stream, stopping daemon, etc.). It is possible that
207 * 			status indicates an error but parts of the response headers
208 * 			and/or body (in one
209 * 			or several frames) were already sent to the client.
210 */
211static void
212spdy_handler_response_queue_result(void * cls,
213								struct SPDYF_Response_Queue *response_queue,
214								enum SPDY_RESPONSE_RESULT status)
215{
216	int streamopened;
217	struct SPDY_Request *request = (struct SPDY_Request *)cls;
218
219	SPDYF_ASSERT( ( (NULL == response_queue->data_frame) &&
220			(NULL != response_queue->control_frame) ) ||
221		      ( (NULL != response_queue->data_frame) &&
222			(NULL == response_queue->control_frame) ),
223		     "response queue must have either control frame or data frame");
224
225	streamopened = !response_queue->stream->is_out_closed;
226
227	response_queue->rrcb(response_queue->rrcb_cls, response_queue->response, request, status, streamopened);
228}
229
230
231int
232(SPDY_init) (enum SPDY_IO_SUBSYSTEM io_subsystem, ...)
233{
234	SPDYF_ASSERT(SPDYF_BUFFER_SIZE >= SPDY_MAX_SUPPORTED_FRAME_SIZE,
235		"Buffer size is less than max supported frame size!");
236	SPDYF_ASSERT(SPDY_MAX_SUPPORTED_FRAME_SIZE >= 32,
237		"Max supported frame size must be bigger than the minimal value!");
238	SPDYF_ASSERT(SPDY_IO_SUBSYSTEM_NONE == spdyf_io_initialized,
239		"SPDY_init must be called only once per program or after SPDY_deinit");
240
241  if(SPDY_IO_SUBSYSTEM_OPENSSL & io_subsystem)
242  {
243    SPDYF_openssl_global_init();
244    spdyf_io_initialized |= SPDY_IO_SUBSYSTEM_OPENSSL;
245  }
246  else if(SPDY_IO_SUBSYSTEM_RAW & io_subsystem)
247  {
248    SPDYF_raw_global_init();
249    spdyf_io_initialized |= SPDY_IO_SUBSYSTEM_RAW;
250  }
251
252	SPDYF_ASSERT(SPDY_IO_SUBSYSTEM_NONE != spdyf_io_initialized,
253		"SPDY_init could not find even one IO subsystem");
254
255	return SPDY_YES;
256}
257
258
259void
260SPDY_deinit ()
261{
262	SPDYF_ASSERT(SPDY_IO_SUBSYSTEM_NONE != spdyf_io_initialized,
263		"SPDY_init has not been called!");
264
265  if(SPDY_IO_SUBSYSTEM_OPENSSL & spdyf_io_initialized)
266    SPDYF_openssl_global_deinit();
267  else if(SPDY_IO_SUBSYSTEM_RAW & spdyf_io_initialized)
268    SPDYF_raw_global_deinit();
269
270  spdyf_io_initialized = SPDY_IO_SUBSYSTEM_NONE;
271}
272
273
274void
275SPDY_run (struct SPDY_Daemon *daemon)
276{
277	if(NULL == daemon)
278	{
279		SPDYF_DEBUG("daemon is NULL");
280		return;
281	}
282
283	SPDYF_run(daemon);
284}
285
286
287int
288SPDY_get_timeout (struct SPDY_Daemon *daemon,
289		     unsigned long long *timeout)
290{
291	if(NULL == daemon)
292	{
293		SPDYF_DEBUG("daemon is NULL");
294		return SPDY_INPUT_ERROR;
295	}
296
297	return SPDYF_get_timeout(daemon,timeout);
298}
299
300
301int
302SPDY_get_fdset (struct SPDY_Daemon *daemon,
303				fd_set *read_fd_set,
304				fd_set *write_fd_set,
305				fd_set *except_fd_set)
306{
307	if(NULL == daemon
308		|| NULL == read_fd_set
309		|| NULL == write_fd_set
310		|| NULL == except_fd_set)
311	{
312		SPDYF_DEBUG("a parameter is NULL");
313		return SPDY_INPUT_ERROR;
314	}
315
316	return SPDYF_get_fdset(daemon,
317				read_fd_set,
318				write_fd_set,
319				except_fd_set,
320				false);
321}
322
323
324struct SPDY_Daemon *
325SPDY_start_daemon (uint16_t port,
326				const char *certfile,
327				const char *keyfile,
328		     SPDY_NewSessionCallback nscb,
329		     SPDY_SessionClosedCallback sccb,
330		     SPDY_NewRequestCallback nrcb,
331		     SPDY_NewDataCallback npdcb,
332		     void * cls,
333		     ...)
334{
335	struct SPDY_Daemon *daemon;
336	va_list valist;
337
338	if(SPDY_IO_SUBSYSTEM_NONE == spdyf_io_initialized)
339	{
340		SPDYF_DEBUG("library not initialized");
341		return NULL;
342	}
343  /*
344   * for now make this checks in framing layer
345	if(NULL == certfile)
346	{
347		SPDYF_DEBUG("certfile is NULL");
348		return NULL;
349	}
350	if(NULL == keyfile)
351	{
352		SPDYF_DEBUG("keyfile is NULL");
353		return NULL;
354	}
355  */
356
357	va_start(valist, cls);
358	daemon = SPDYF_start_daemon_va ( port,
359				certfile,
360				keyfile,
361		      nscb,
362		      sccb,
363		      nrcb,
364		      npdcb,
365		      &spdy_handler_new_stream,
366		      &spdy_handler_new_data,
367		      cls,
368		      NULL,
369		      valist
370		     );
371	va_end(valist);
372
373	return daemon;
374}
375
376
377void
378SPDY_stop_daemon (struct SPDY_Daemon *daemon)
379{
380	if(NULL == daemon)
381	{
382		SPDYF_DEBUG("daemon is NULL");
383		return;
384	}
385
386	SPDYF_stop_daemon(daemon);
387}
388
389
390struct SPDY_Response *
391SPDY_build_response(int status,
392					const char * statustext,
393					const char * version,
394					struct SPDY_NameValue * headers,
395					const void * data,
396					size_t size)
397{
398	struct SPDY_Response *response = NULL;
399	struct SPDY_NameValue ** all_headers = NULL; //TODO maybe array in stack is enough
400	char *fullstatus = NULL;
401	int ret;
402	int num_hdr_containers = 1;
403
404	if(NULL == version)
405	{
406		SPDYF_DEBUG("version is NULL");
407		return NULL;
408	}
409
410	if(NULL == (response = malloc(sizeof(struct SPDY_Response))))
411		goto free_and_fail;
412	memset(response, 0, sizeof(struct SPDY_Response));
413
414	if(NULL != headers && !SPDYF_name_value_is_empty(headers))
415		num_hdr_containers = 2;
416
417	if(NULL == (all_headers = malloc(num_hdr_containers * sizeof(struct SPDY_NameValue *))))
418		goto free_and_fail;
419	memset(all_headers, 0, num_hdr_containers * sizeof(struct SPDY_NameValue *));
420
421	if(2 == num_hdr_containers)
422		all_headers[1] = headers;
423
424	if(NULL == (all_headers[0] = SPDY_name_value_create()))
425		goto free_and_fail;
426
427	if(NULL == statustext)
428		ret = asprintf(&fullstatus, "%i", status);
429	else
430		ret = asprintf(&fullstatus, "%i %s", status, statustext);
431	if(-1 == ret)
432		goto free_and_fail;
433
434	if(SPDY_YES != SPDY_name_value_add(all_headers[0], ":status", fullstatus))
435		goto free_and_fail;
436
437	free(fullstatus);
438	fullstatus = NULL;
439
440	if(SPDY_YES != SPDY_name_value_add(all_headers[0], ":version", version))
441		goto free_and_fail;
442
443	if(0 >= (response->headers_size = SPDYF_name_value_to_stream(all_headers,
444												num_hdr_containers,
445												&(response->headers))))
446		goto free_and_fail;
447
448	SPDY_name_value_destroy(all_headers[0]);
449	free(all_headers);
450  all_headers = NULL;
451
452	if(size > 0)
453	{
454		//copy the data to the response object
455		if(NULL == (response->data = malloc(size)))
456		{
457			free(response->headers);
458			goto free_and_fail;
459		}
460		memcpy(response->data, data, size);
461		response->data_size = size;
462	}
463
464	return response;
465
466	//for GOTO
467	free_and_fail:
468
469	free(fullstatus);
470	if(NULL != all_headers)
471		SPDY_name_value_destroy(all_headers[0]);
472	free(all_headers);
473	free(response);
474
475	return NULL;
476}
477
478
479struct SPDY_Response *
480SPDY_build_response_with_callback(int status,
481					const char * statustext,
482					const char * version,
483					struct SPDY_NameValue * headers,
484					SPDY_ResponseCallback rcb,
485					void *rcb_cls,
486					uint32_t block_size)
487{
488	struct SPDY_Response *response;
489
490	if(NULL == rcb)
491	{
492		SPDYF_DEBUG("rcb is NULL");
493		return NULL;
494	}
495	if(block_size > SPDY_MAX_SUPPORTED_FRAME_SIZE)
496	{
497		SPDYF_DEBUG("block_size is wrong");
498		return NULL;
499	}
500
501	if(0 == block_size)
502		block_size = SPDY_MAX_SUPPORTED_FRAME_SIZE;
503
504	response = SPDY_build_response(status,
505					statustext,
506					version,
507					headers,
508					NULL,
509					0);
510
511	if(NULL == response)
512	{
513		return NULL;
514	}
515
516	response->rcb = rcb;
517	response->rcb_cls = rcb_cls;
518	response->rcb_block_size = block_size;
519
520	return response;
521}
522
523
524int
525SPDY_queue_response (struct SPDY_Request * request,
526					struct SPDY_Response *response,
527					bool closestream,
528					bool consider_priority,
529					SPDY_ResponseResultCallback rrcb,
530					void * rrcb_cls)
531{
532	struct SPDYF_Response_Queue *headers_to_queue;
533	struct SPDYF_Response_Queue *body_to_queue;
534	SPDYF_ResponseQueueResultCallback frqcb = NULL;
535	void *frqcb_cls = NULL;
536	int int_consider_priority = consider_priority ? SPDY_YES : SPDY_NO;
537
538	if(NULL == request)
539	{
540		SPDYF_DEBUG("request is NULL");
541		return SPDY_INPUT_ERROR;
542	}
543	if(NULL == response)
544	{
545		SPDYF_DEBUG("request is NULL");
546		return SPDY_INPUT_ERROR;
547	}
548
549	if(request->stream->is_out_closed
550		|| SPDY_SESSION_STATUS_CLOSING == request->stream->session->status)
551		return SPDY_NO;
552
553	if(NULL != rrcb)
554	{
555		frqcb_cls = request;
556		frqcb = &spdy_handler_response_queue_result;
557	}
558
559	if(response->data_size > 0)
560	{
561		//SYN_REPLY and DATA will be queued
562
563		if(NULL == (headers_to_queue = SPDYF_response_queue_create(false,
564							response->headers,
565							response->headers_size,
566							response,
567							request->stream,
568							false,
569							NULL,
570							NULL,
571							NULL,
572							NULL)))
573		{
574			return SPDY_NO;
575		}
576
577		if(NULL == (body_to_queue = SPDYF_response_queue_create(true,
578							response->data,
579							response->data_size,
580							response,
581							request->stream,
582							closestream,
583							frqcb,
584							frqcb_cls,
585							rrcb,
586							rrcb_cls)))
587		{
588			SPDYF_response_queue_destroy(headers_to_queue);
589			return SPDY_NO;
590		}
591
592		SPDYF_queue_response (headers_to_queue,
593							request->stream->session,
594							int_consider_priority);
595
596		SPDYF_queue_response (body_to_queue,
597							request->stream->session,
598							int_consider_priority);
599	}
600	else if(NULL == response->rcb)
601	{
602		//no "body" will be queued, e.g. HTTP 404 without body
603
604		if(NULL == (headers_to_queue = SPDYF_response_queue_create(false,
605							response->headers,
606							response->headers_size,
607							response,
608							request->stream,
609							closestream,
610							frqcb,
611							frqcb_cls,
612							rrcb,
613							rrcb_cls)))
614		{
615			return SPDY_NO;
616		}
617
618		SPDYF_queue_response (headers_to_queue,
619							request->stream->session,
620							int_consider_priority);
621	}
622	else
623	{
624		//response with callbacks
625
626		if(NULL == (headers_to_queue = SPDYF_response_queue_create(false,
627							response->headers,
628							response->headers_size,
629							response,
630							request->stream,
631							false,
632							NULL,
633							NULL,
634							NULL,
635							NULL)))
636		{
637			return SPDY_NO;
638		}
639
640		if(NULL == (body_to_queue = SPDYF_response_queue_create(true,
641							response->data,
642							response->data_size,
643							response,
644							request->stream,
645							closestream,
646							frqcb,
647							frqcb_cls,
648							rrcb,
649							rrcb_cls)))
650		{
651			SPDYF_response_queue_destroy(headers_to_queue);
652			return SPDY_NO;
653		}
654
655		SPDYF_queue_response (headers_to_queue,
656							request->stream->session,
657							int_consider_priority);
658
659		SPDYF_queue_response (body_to_queue,
660							request->stream->session,
661							int_consider_priority);
662	}
663
664	return SPDY_YES;
665}
666
667
668socklen_t
669SPDY_get_remote_addr(struct SPDY_Session * session,
670					 struct sockaddr ** addr)
671{
672	if(NULL == session)
673	{
674		SPDYF_DEBUG("session is NULL");
675		return 0;
676	}
677
678	*addr = session->addr;
679
680	return session->addr_len;
681}
682
683
684struct SPDY_Session *
685SPDY_get_session_for_request(const struct SPDY_Request * request)
686{
687	if(NULL == request)
688	{
689		SPDYF_DEBUG("request is NULL");
690		return NULL;
691	}
692
693	return request->stream->session;
694}
695
696
697void *
698SPDY_get_cls_from_session(struct SPDY_Session * session)
699{
700	if(NULL == session)
701	{
702		SPDYF_DEBUG("session is NULL");
703		return NULL;
704	}
705
706	return session->user_cls;
707}
708
709
710void
711SPDY_set_cls_to_session(struct SPDY_Session * session,
712							void * cls)
713{
714	if(NULL == session)
715	{
716		SPDYF_DEBUG("session is NULL");
717		return;
718	}
719
720	session->user_cls = cls;
721}
722
723
724void *
725SPDY_get_cls_from_request(struct SPDY_Request * request)
726{
727	if(NULL == request)
728	{
729		SPDYF_DEBUG("request is NULL");
730		return NULL;
731	}
732
733	return request->user_cls;
734}
735
736
737void
738SPDY_set_cls_to_request(struct SPDY_Request * request,
739							void * cls)
740{
741	if(NULL == request)
742	{
743		SPDYF_DEBUG("request is NULL");
744		return;
745	}
746
747	request->user_cls = cls;
748}
749