Home | History | Annotate | Download | only in microspdy
      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
     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
     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
    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
    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
    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
    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
    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
    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 *
    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
    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 *
    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 *
    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
    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
    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 *
    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 *
    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
    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 *
    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
    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