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