GNU libmicrohttpd  0.9.29
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
structures.c
Go to the documentation of this file.
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 
26 #include "platform.h"
27 #include "structures.h"
28 #include "internal.h"
29 #include "session.h"
30 //TODO not for here?
31 #include <ctype.h>
32 
33 
34 int
36 {
37  SPDYF_ASSERT(NULL != container, "NULL is not an empty container!");
38  return (NULL == container->name && NULL == container->value) ? SPDY_YES : SPDY_NO;
39 }
40 
41 struct SPDY_NameValue *
43 {
44  struct SPDY_NameValue *pair;
45 
46  if(NULL == (pair = malloc(sizeof(struct SPDY_NameValue))))
47  return NULL;
48 
49  memset (pair, 0, sizeof (struct SPDY_NameValue));
50 
51  return pair;
52 }
53 
54 
55 int
57  const char *name,
58  const char *value)
59 {
60  unsigned int i;
61  unsigned int len;
62  struct SPDY_NameValue *pair;
63  struct SPDY_NameValue *temp;
64  char **temp_value;
65  char *temp_string;
66 
67  if(NULL == container || NULL == name || NULL == value || 0 == (len = strlen(name)))
68  return SPDY_INPUT_ERROR;
69  //TODO there is old code handling value==NULL
70  //update it to handle strlen(value)==0
71 
72  for(i=0; i<len; ++i)
73  {
74  if(isupper((int) name[i]))
75  return SPDY_INPUT_ERROR;
76  }
77 
78  if(SPDYF_name_value_is_empty(container))
79  {
80  //container is empty/just created
81  if (NULL == (container->name = strdup (name)))
82  {
83  return SPDY_NO;
84  }
85  if (NULL == (container->value = malloc(sizeof(char *))))
86  {
87  free(container->name);
88  return SPDY_NO;
89  }
90  /*if(NULL == value)
91  container->value[0] = NULL;
92  else */if (NULL == (container->value[0] = strdup (value)))
93  {
94  free(container->value);
95  free(container->name);
96  return SPDY_NO;
97  }
98  container->num_values = 1;
99  return SPDY_YES;
100  }
101 
102  pair = container;
103  while(NULL != pair)
104  {
105  if(0 == strcmp(pair->name, name))
106  {
107  //the value will be added to this pair
108  break;
109  }
110  pair = pair->next;
111  }
112 
113  if(NULL == pair)
114  {
115  //the name doesn't exist in container, add new pair
116  if(NULL == (pair = malloc(sizeof(struct SPDY_NameValue))))
117  return SPDY_NO;
118 
119  memset(pair, 0, sizeof(struct SPDY_NameValue));
120 
121  if (NULL == (pair->name = strdup (name)))
122  {
123  free(pair);
124  return SPDY_NO;
125  }
126  if (NULL == (pair->value = malloc(sizeof(char *))))
127  {
128  free(pair->name);
129  free(pair);
130  return SPDY_NO;
131  }
132  /*if(NULL == value)
133  pair->value[0] = NULL;
134  else */if (NULL == (pair->value[0] = strdup (value)))
135  {
136  free(pair->value);
137  free(pair->name);
138  free(pair);
139  return SPDY_NO;
140  }
141  pair->num_values = 1;
142 
143  temp = container;
144  while(NULL != temp->next)
145  temp = temp->next;
146  temp->next = pair;
147  pair->prev = temp;
148 
149  return SPDY_YES;
150  }
151 
152  //check for duplication (case sensitive)
153  for(i=0; i<pair->num_values; ++i)
154  if(0 == strcmp(pair->value[i], value))
155  return SPDY_NO;
156 
157  if(strlen(pair->value[0]) > 0)
158  {
159  //the value will be appended to the others for this name
160  if (NULL == (temp_value = malloc((pair->num_values + 1) * sizeof(char *))))
161  {
162  return SPDY_NO;
163  }
164  memcpy(temp_value, pair->value, pair->num_values * sizeof(char *));
165  if (NULL == (temp_value[pair->num_values] = strdup (value)))
166  {
167  free(temp_value);
168  return SPDY_NO;
169  }
170  free(pair->value);
171  pair->value = temp_value;
172  ++pair->num_values;
173  return SPDY_YES;
174  }
175 
176  //just replace the empty value
177 
178  if (NULL == (temp_string = strdup (value)))
179  {
180  return SPDY_NO;
181  }
182  free(pair->value[0]);
183  pair->value[0] = temp_string;
184 
185  return SPDY_YES;
186 }
187 
188 
189 const char * const *
191  const char *name,
192  int *num_values)
193 {
194  struct SPDY_NameValue *temp = container;
195 
196  if(NULL == container || NULL == name || NULL == num_values)
197  return NULL;
198  if(SPDYF_name_value_is_empty(container))
199  return NULL;
200 
201  do
202  {
203  if(strcmp(name, temp->name) == 0)
204  {
205  *num_values = temp->num_values;
206  return (const char * const *)temp->value;
207  }
208 
209  temp = temp->next;
210  }
211  while(NULL != temp);
212 
213  return NULL;
214 }
215 
216 
217 void
219 {
220  unsigned int i;
221  struct SPDY_NameValue *temp = container;
222 
223  while(NULL != temp)
224  {
225  container = container->next;
226  free(temp->name);
227  for(i=0; i<temp->num_values; ++i)
228  free(temp->value[i]);
229  free(temp->value);
230  free(temp);
231  temp=container;
232  }
233 }
234 
235 
236 int
238  SPDY_NameValueIterator iterator,
239  void *iterator_cls)
240 {
241  int count;
242  int ret;
243  struct SPDY_NameValue *temp = container;
244 
245  if(NULL == container)
246  return SPDY_INPUT_ERROR;
247 
248  //check if container is an empty struct
249  if(SPDYF_name_value_is_empty(container))
250  return 0;
251 
252  count = 0;
253 
254  if(NULL == iterator)
255  {
256  do
257  {
258  ++count;
259  temp=temp->next;
260  }
261  while(NULL != temp);
262 
263  return count;
264  }
265 
266  //code duplication for avoiding if here
267  do
268  {
269  ++count;
270  ret = iterator(iterator_cls, temp->name, (const char * const *)temp->value, temp->num_values);
271  temp=temp->next;
272  }
273  while(NULL != temp && SPDY_YES == ret);
274 
275  return count;
276 }
277 
278 void
280 {
281  if(NULL == response)
282  return;
283  free(response->data);
284  free(response->headers);
285  free(response);
286 }
287 
288 
289 struct SPDYF_Response_Queue *
291  void *data,
292  size_t data_size,
293  struct SPDY_Response *response,
294  struct SPDYF_Stream *stream,
295  bool closestream,
297  void *frqcb_cls,
299  void *rrcb_cls)
300 {
301  struct SPDYF_Response_Queue *head = NULL;
302  struct SPDYF_Response_Queue *prev;
303  struct SPDYF_Response_Queue *response_to_queue;
304  struct SPDYF_Control_Frame *control_frame;
305  struct SPDYF_Data_Frame *data_frame;
306  unsigned int i;
307  bool is_last;
308 
309  SPDYF_ASSERT((! is_data)
310  || ((0 == data_size) && (NULL != response->rcb))
311  || ((0 < data_size) && (NULL == response->rcb)),
312  "either data or request->rcb must not be null");
313 
314  if (is_data && (data_size > SPDY_MAX_SUPPORTED_FRAME_SIZE))
315  {
316  //separate the data in more frames and add them to the queue
317 
318  prev=NULL;
319  for(i = 0; i < data_size; i += SPDY_MAX_SUPPORTED_FRAME_SIZE)
320  {
321  is_last = (i + SPDY_MAX_SUPPORTED_FRAME_SIZE) >= data_size;
322 
323  if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
324  goto free_and_fail;
325 
326  memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
327  if(0 == i)
328  head = response_to_queue;
329 
330  if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame))))
331  {
332  free(response_to_queue);
333  goto free_and_fail;
334  }
335  memset(data_frame, 0, sizeof(struct SPDYF_Data_Frame));
336  data_frame->control_bit = 0;
337  data_frame->stream_id = stream->stream_id;
338  if(is_last && closestream)
339  data_frame->flags |= SPDY_DATA_FLAG_FIN;
340 
341  response_to_queue->data_frame = data_frame;
343  response_to_queue->is_data = is_data;
344  response_to_queue->stream = stream;
345  if(is_last)
346  {
347  response_to_queue->frqcb = frqcb;
348  response_to_queue->frqcb_cls = frqcb_cls;
349  response_to_queue->rrcb = rrcb;
350  response_to_queue->rrcb_cls = rrcb_cls;
351  }
352  response_to_queue->data = data + i;
353  response_to_queue->data_size = is_last
354  ? (data_size - 1) % SPDY_MAX_SUPPORTED_FRAME_SIZE + 1
356  response_to_queue->response = response;
357 
358  response_to_queue->prev = prev;
359  if(NULL != prev)
360  prev->next = response_to_queue;
361  prev = response_to_queue;
362  }
363 
364  return head;
365 
366  //for GOTO
367  free_and_fail:
368  while(NULL != head)
369  {
370  response_to_queue = head;
371  head = head->next;
372  free(response_to_queue->data_frame);
373  free(response_to_queue);
374  }
375  return NULL;
376  }
377 
378  //create only one frame for data, data with callback or control frame
379 
380  if(NULL == (response_to_queue = malloc(sizeof(struct SPDYF_Response_Queue))))
381  {
382  return NULL;
383  }
384  memset(response_to_queue, 0, sizeof(struct SPDYF_Response_Queue));
385 
386  if(is_data)
387  {
388  if(NULL == (data_frame = malloc(sizeof(struct SPDYF_Data_Frame))))
389  {
390  free(response_to_queue);
391  return NULL;
392  }
393  memset(data_frame, 0, sizeof(struct SPDYF_Data_Frame));
394  data_frame->control_bit = 0;
395  data_frame->stream_id = stream->stream_id;
396  if(closestream && NULL == response->rcb)
397  data_frame->flags |= SPDY_DATA_FLAG_FIN;
398 
399  response_to_queue->data_frame = data_frame;
401  }
402  else
403  {
404  if(NULL == (control_frame = malloc(sizeof(struct SPDYF_Control_Frame))))
405  {
406  free(response_to_queue);
407  return NULL;
408  }
409  memset(control_frame, 0, sizeof(struct SPDYF_Control_Frame));
410  control_frame->control_bit = 1;
411  control_frame->version = SPDY_VERSION;
412  control_frame->type = SPDY_CONTROL_FRAME_TYPES_SYN_REPLY;
413  if(closestream)
414  control_frame->flags |= SPDY_SYN_REPLY_FLAG_FIN;
415 
416  response_to_queue->control_frame = control_frame;
418  }
419 
420  response_to_queue->is_data = is_data;
421  response_to_queue->stream = stream;
422  response_to_queue->frqcb = frqcb;
423  response_to_queue->frqcb_cls = frqcb_cls;
424  response_to_queue->rrcb = rrcb;
425  response_to_queue->rrcb_cls = rrcb_cls;
426  response_to_queue->data = data;
427  response_to_queue->data_size = data_size;
428  response_to_queue->response = response;
429 
430  return response_to_queue;
431 }
432 
433 
434 void
436 {
437  //data is not copied to the struct but only linked
438  //but this is not valid for GOAWAY and RST_STREAM
439  if(!response_queue->is_data
440  && (SPDY_CONTROL_FRAME_TYPES_RST_STREAM == response_queue->control_frame->type
441  || SPDY_CONTROL_FRAME_TYPES_GOAWAY == response_queue->control_frame->type))
442  {
443  free(response_queue->data);
444  }
445  if(response_queue->is_data)
446  free(response_queue->data_frame);
447  else
448  free(response_queue->control_frame);
449 
450  free(response_queue);
451 }
452 
453 
454 /* Needed by testcase to be extern -- should this be
455  in the header? */
456 _MHD_EXTERN ssize_t
458  int num_containers,
459  void **stream)
460 {
461  size_t size;
462  int32_t num_pairs = 0;
463  int32_t value_size;
464  int32_t name_size;
465  int32_t temp;
466  unsigned int i;
467  unsigned int offset;
468  unsigned int value_offset;
469  struct SPDY_NameValue * iterator;
470  int j;
471 
472  size = 4; //for num pairs
473 
474  for(j=0; j<num_containers; ++j)
475  {
476  iterator = container[j];
477  while(iterator != NULL)
478  {
479  ++num_pairs;
480  size += 4 + strlen(iterator->name); //length + string
481 
482  SPDYF_ASSERT(iterator->num_values>0, "num_values is 0");
483 
484  size += 4; //value length
485 
486  for(i=0; i<iterator->num_values; ++i)
487  {
488  //if(NULL == iterator->value[i])
489  // continue;
490  size += strlen(iterator->value[i]); // string
491  if(i/* || !strlen(iterator->value[i])*/) ++size; //NULL separator
492  }
493 
494  iterator = iterator->next;
495  }
496  }
497 
498  if(NULL == (*stream = malloc(size)))
499  {
500  return -1;
501  }
502 
503  //put num_pairs to the stream
504  num_pairs = htonl(num_pairs);
505  memcpy(*stream, &num_pairs, 4);
506  offset = 4;
507 
508  //put all other headers to the stream
509  for(j=0; j<num_containers; ++j)
510  {
511  iterator = container[j];
512  while(iterator != NULL)
513  {
514  name_size = strlen(iterator->name);
515  temp = htonl(name_size);
516  memcpy(*stream + offset, &temp, 4);
517  offset += 4;
518  strncpy(*stream + offset, iterator->name, name_size);
519  offset += name_size;
520 
521  value_offset = offset;
522  offset += 4;
523  for(i=0; i<iterator->num_values; ++i)
524  {
525  if(i /*|| !strlen(iterator->value[0])*/)
526  {
527  memset(*stream + offset, 0, 1);
528  ++offset;
529  //if(!i) continue;
530  }
531  //else if(NULL != iterator->value[i])
532  //{
533  strncpy(*stream + offset, iterator->value[i], strlen(iterator->value[i]));
534  offset += strlen(iterator->value[i]);
535  //}
536  }
537  value_size = offset - value_offset - 4;
538  value_size = htonl(value_size);
539  memcpy(*stream + value_offset, &value_size, 4);
540 
541  iterator = iterator->next;
542  }
543  }
544 
545  SPDYF_ASSERT(offset == size,"offset is wrong");
546 
547  return size;
548 }
549 
550 
551 /* Needed by testcase to be extern -- should this be
552  in the header? */
553 _MHD_EXTERN int
555  size_t size,
556  struct SPDY_NameValue ** container)
557 {
558  int32_t num_pairs;
559  int32_t value_size;
560  int32_t name_size;
561  int i;
562  unsigned int offset = 0;
563  unsigned int value_end_offset;
564  char *name;
565  char *value;
566 
567  if(NULL == (*container = SPDY_name_value_create ()))
568  {
569  return SPDY_NO;
570  }
571 
572  //get number of pairs
573  memcpy(&num_pairs, stream, 4);
574  offset = 4;
575  num_pairs = ntohl(num_pairs);
576 
577  if(num_pairs > 0)
578  {
579  for(i = 0; i < num_pairs; ++i)
580  {
581  //get name size
582  memcpy(&name_size, stream + offset, 4);
583  offset += 4;
584  name_size = ntohl(name_size);
585  //get name
586  if(NULL == (name = strndup(stream + offset, name_size)))
587  {
588  SPDY_name_value_destroy(*container);
589  return SPDY_NO;
590  }
591  offset+=name_size;
592 
593  //get value size
594  memcpy(&value_size, stream + offset, 4);
595  offset += 4;
596  value_size = ntohl(value_size);
597  value_end_offset = offset + value_size;
598  //get value
599  do
600  {
601  if(NULL == (value = strndup(stream + offset, value_size)))
602  {
603  free(name);
604  SPDY_name_value_destroy(*container);
605  return SPDY_NO;
606  }
607  offset += strlen(value);
608  if(offset < value_end_offset)
609  ++offset; //NULL separator
610 
611  //add name/value to the struct
612  if(SPDY_YES != SPDY_name_value_add(*container, name, value))
613  {
614  free(name);
615  free(value);
616  SPDY_name_value_destroy(*container);
617  return SPDY_NO;
618  }
619  free(value);
620  }
621  while(offset < value_end_offset);
622 
623  free(name);
624 
625  if(offset != value_end_offset)
626  {
627  SPDY_name_value_destroy(*container);
628  return SPDY_INPUT_ERROR;
629  }
630  }
631  }
632 
633  if(offset == size)
634  return SPDY_YES;
635 
636  SPDY_name_value_destroy(*container);
637  return SPDY_INPUT_ERROR;
638 }
struct SPDYF_Response_Queue * SPDYF_response_queue_create(bool is_data, void *data, size_t data_size, struct SPDY_Response *response, struct SPDYF_Stream *stream, bool closestream, SPDYF_ResponseQueueResultCallback frqcb, void *frqcb_cls, SPDY_ResponseResultCallback rrcb, void *rrcb_cls)
Definition: structures.c:290
const char *const * SPDY_name_value_lookup(struct SPDY_NameValue *container, const char *name, int *num_values)
Definition: structures.c:190
#define NULL
Definition: reason_phrase.c:31
#define SPDY_YES
Definition: microspdy.h:93
_MHD_EXTERN ssize_t SPDYF_name_value_to_stream(struct SPDY_NameValue *container[], int num_containers, void **stream)
Definition: structures.c:457
int SPDY_name_value_add(struct SPDY_NameValue *container, const char *name, const char *value)
Definition: structures.c:56
struct SPDYF_Control_Frame * control_frame
Definition: structures.h:430
TCP connection/SPDY session handling.
int SPDYF_handler_write_data(struct SPDY_Session *session)
Definition: session.c:570
void SPDYF_response_queue_destroy(struct SPDYF_Response_Queue *response_queue)
Definition: structures.c:435
int(* process_response_handler)(struct SPDY_Session *session)
Definition: structures.h:446
internal functions and macros for the framing layer
platform-specific includes for libmicrohttpd
#define SPDY_INPUT_ERROR
Definition: microspdy.h:105
internal and public structures – most of the structs used by the library are defined here ...
struct SPDYF_Response_Queue * prev
Definition: structures.h:414
_MHD_EXTERN int SPDYF_name_value_from_stream(void *stream, size_t size, struct SPDY_NameValue **container)
Definition: structures.c:554
int SPDYF_name_value_is_empty(struct SPDY_NameValue *container)
Definition: structures.c:35
SPDYF_ResponseQueueResultCallback frqcb
Definition: structures.h:452
#define SPDY_MAX_SUPPORTED_FRAME_SIZE
Definition: microspdy.h:117
SPDY_ResponseCallback rcb
Definition: structures.h:1022
#define SPDY_NO
Definition: microspdy.h:98
#define _MHD_EXTERN
Definition: microhttpd.h:175
struct SPDY_NameValue * next
Definition: structures.h:491
int(* SPDY_NameValueIterator)(void *cls, const char *name, const char *const *value, int num_values)
Definition: microspdy.h:638
void * headers
Definition: structures.h:1009
unsigned int num_values
Definition: structures.h:512
void(* SPDY_ResponseResultCallback)(void *cls, struct SPDY_Response *response, struct SPDY_Request *request, enum SPDY_RESPONSE_RESULT status, bool streamopened)
Definition: microspdy.h:753
#define SPDY_VERSION
Definition: microspdy.h:110
void(* SPDYF_ResponseQueueResultCallback)(void *cls, struct SPDYF_Response_Queue *response_queue, enum SPDY_RESPONSE_RESULT status)
Definition: structures.h:370
char ** value
Definition: structures.h:507
void SPDY_name_value_destroy(struct SPDY_NameValue *container)
Definition: structures.c:218
struct SPDYF_Data_Frame * data_frame
Definition: structures.h:436
#define SPDYF_ASSERT(expr, msg)
Definition: internal.h:79
int SPDY_name_value_iterate(struct SPDY_NameValue *container, SPDY_NameValueIterator iterator, void *iterator_cls)
Definition: structures.c:237
struct SPDY_NameValue * prev
Definition: structures.h:496
SPDY_ResponseResultCallback rrcb
Definition: structures.h:462
uint32_t stream_id
Definition: structures.h:549
void SPDY_destroy_response(struct SPDY_Response *response)
Definition: structures.c:279
struct SPDYF_Response_Queue * next
Definition: structures.h:409
struct SPDY_NameValue * SPDY_name_value_create()
Definition: structures.c:42
int SPDYF_handler_write_syn_reply(struct SPDY_Session *session)
Definition: session.c:422
struct SPDYF_Stream * stream
Definition: structures.h:419
struct SPDY_Response * response
Definition: structures.h:424