• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
34 void
spdy_callback_response_done(void * cls,struct SPDY_Response * response,struct SPDY_Request * request,enum SPDY_RESPONSE_RESULT status,bool streamopened)35 spdy_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  */
58 static int
spdy_handler_new_stream(void * cls,struct SPDYF_Stream * stream)59 spdy_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  */
186 static int
spdy_handler_new_data(void * cls,struct SPDYF_Stream * stream,const void * buf,size_t size,bool more)187 spdy_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  */
211 static void
spdy_handler_response_queue_result(void * cls,struct SPDYF_Response_Queue * response_queue,enum SPDY_RESPONSE_RESULT status)212 spdy_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 
231 int
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 
259 void
SPDY_deinit()260 SPDY_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 
274 void
SPDY_run(struct SPDY_Daemon * daemon)275 SPDY_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 
287 int
SPDY_get_timeout(struct SPDY_Daemon * daemon,unsigned long long * timeout)288 SPDY_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 
301 int
SPDY_get_fdset(struct SPDY_Daemon * daemon,fd_set * read_fd_set,fd_set * write_fd_set,fd_set * except_fd_set)302 SPDY_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 
324 struct SPDY_Daemon *
SPDY_start_daemon(uint16_t port,const char * certfile,const char * keyfile,SPDY_NewSessionCallback nscb,SPDY_SessionClosedCallback sccb,SPDY_NewRequestCallback nrcb,SPDY_NewDataCallback npdcb,void * cls,...)325 SPDY_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 
377 void
SPDY_stop_daemon(struct SPDY_Daemon * daemon)378 SPDY_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 
390 struct SPDY_Response *
SPDY_build_response(int status,const char * statustext,const char * version,struct SPDY_NameValue * headers,const void * data,size_t size)391 SPDY_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 
479 struct SPDY_Response *
SPDY_build_response_with_callback(int status,const char * statustext,const char * version,struct SPDY_NameValue * headers,SPDY_ResponseCallback rcb,void * rcb_cls,uint32_t block_size)480 SPDY_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 
524 int
SPDY_queue_response(struct SPDY_Request * request,struct SPDY_Response * response,bool closestream,bool consider_priority,SPDY_ResponseResultCallback rrcb,void * rrcb_cls)525 SPDY_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 
668 socklen_t
SPDY_get_remote_addr(struct SPDY_Session * session,struct sockaddr ** addr)669 SPDY_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 
684 struct SPDY_Session *
SPDY_get_session_for_request(const struct SPDY_Request * request)685 SPDY_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 
697 void *
SPDY_get_cls_from_session(struct SPDY_Session * session)698 SPDY_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 
710 void
SPDY_set_cls_to_session(struct SPDY_Session * session,void * cls)711 SPDY_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 
724 void *
SPDY_get_cls_from_request(struct SPDY_Request * request)725 SPDY_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 
737 void
SPDY_set_cls_to_request(struct SPDY_Request * request,void * cls)738 SPDY_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