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