source: roaraudio/plugins/universal/protocol-http.c @ 5722:00b33daf291c

Last change on this file since 5722:00b33daf291c was 5722:00b33daf291c, checked in by phi, 11 years ago

corrected version

File size: 20.5 KB
Line 
1//protocol-http.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2011-2012
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include <roaraudio.h>
27
28struct resource_handle;
29
30enum ctl_cmd {
31 CMD_SET_CLIENTNAME
32};
33
34enum status {
35 STATUS_WAITING_FOR_HEADERS = 0,
36 STATUS_END_OF_HEADER,
37 STATUS_BAD_HEADER,
38 STATUS_RUNNING_DATA,
39 STATUS_DONE
40};
41
42struct input_source {
43 int userdata_si;
44 void * userdata_vp;
45 ssize_t offset;
46 struct roar_vio_calls * vio;
47 struct roar_vio_calls vio_store;
48};
49
50struct http_client {
51 enum status status;
52 struct roar_buffer * input_buffer;
53 char * method;
54 char * proto;
55 char * uri;
56 char * path, * query_string;
57 void * headersstore;
58 struct roar_keyval * headers;
59 ssize_t headerslen;
60 const struct resource_handle * resource;
61 struct input_source input;
62 struct roar_dl_librarypara * pluginpara;
63 int clientid;
64};
65
66struct resource_handle {
67 const char  * uri;
68 const char  * rawdata;
69 const ssize_t rawlen;
70 const char  * content_type;
71 int (*header_send)(struct http_client * self, struct roar_buffer ** obuffer);
72 int (*body_send)(struct http_client * self, struct roar_buffer ** obuffer);
73};
74
75static struct {
76 enum {
77  HOSTTYPE_GENERIC = 0,
78  HOSTTYPE_ROARD
79 } hosttype;
80 union {
81  struct {
82   int (*clients_set_name)(int id, const char * name);
83  } roard;
84 } hostspec;
85} __host = {.hosttype = HOSTTYPE_GENERIC};
86
87static int header_send(struct roar_buffer ** obuffer, int status, const char * msg, const char * content_type, ssize_t len);
88
89static int slow_zero_stream(struct http_client * self, struct roar_buffer ** obuffer) {
90 struct roar_buffer * buffer;
91 void * data;
92
93 self->status = STATUS_RUNNING_DATA;
94
95 if ( roar_buffer_new_data(&buffer, 1, &data) == -1 )
96  return -1;
97
98 *((char*)data) = 0;
99
100 if ( roar_buffer_moveintoqueue(obuffer, &buffer) == -1 ) {
101  roar_buffer_free(buffer);
102  return -1;
103 }
104
105 return 0;
106}
107
108static const char * __res_vio_content_type_get(struct http_client * self) {
109 const char * point = rindex(self->path, '.');
110
111 if ( point == NULL )
112  return NULL;
113
114 point++;
115
116 if ( !strcmp(point, "txt") || !strcmp(point, "text") ) {
117  return "text/plain";
118 } else if ( !strcmp(point, "htm") || !strcmp(point, "html") ) {
119  return "text/html";
120 } else if ( !strcmp(point, "css") ) {
121  return "text/css";
122 } else if ( !strcmp(point, "png") ) {
123  return "image/png";
124 } else if ( !strcmp(point, "jpg") || !strcmp(point, "jpeg") ) {
125  return "image/jpeg";
126 }
127
128 return NULL;
129}
130
131static int __res_vio_header_send(struct http_client * self, struct roar_buffer ** obuffer) {
132 struct roar_keyval * path;
133 char filename[1024];
134 const char * slash = "/";
135 const char * content_type = NULL;
136
137 if ( self->pluginpara == NULL ) {
138  roar_err_set(ROAR_ERROR_INVAL);
139  return -1;
140 }
141
142 path = roar_keyval_lookup(self->pluginpara->argv, "webroot", self->pluginpara->argc, 1);
143 if ( path == NULL ) {
144  if ( roar_error == ROAR_ERROR_NOENT )
145   roar_err_set(ROAR_ERROR_INVAL);
146  return -1;
147 }
148
149 if ( path->value == NULL ) {
150  roar_err_set(ROAR_ERROR_INVAL);
151  return -1;
152 }
153
154 if ( strstr(self->path, "..") != NULL || strstr(self->path, "#") != NULL ) {
155  roar_err_set(ROAR_ERROR_INVAL);
156  return -1;
157 }
158
159 if ( (roar_mm_strlen(path->value) + roar_mm_strlen(self->path) + 2) > sizeof(filename) ) {
160  roar_err_set(ROAR_ERROR_NAMETOOLONG);
161  return -1;
162 }
163
164 if ( self->path[0] == '/' || path->value[strlen(path->value)-1] == '/' )
165  slash = "";
166
167 snprintf(filename, sizeof(filename), "%s%s%s", path->value, slash, self->path);
168
169
170 self->input.vio = &(self->input.vio_store);
171 if ( roar_vio_open_dstr_simple(self->input.vio, filename, ROAR_VIOF_READ|ROAR_VIOF_NONBLOCK) == -1 ) {
172  return -1;
173 }
174
175 if ( roar_vio_ctl(self->input.vio, ROAR_VIO_CTL_GET_MIMETYPE, &content_type) == -1 )
176  content_type = NULL;
177
178 if ( content_type == NULL )
179  content_type = __res_vio_content_type_get(self);
180
181 header_send(obuffer, 200, NULL, content_type, -1);
182
183 self->status = STATUS_RUNNING_DATA;
184 return 0;
185}
186
187static int __res_vio_body_send(struct http_client * self, struct roar_buffer ** obuffer) {
188 const size_t len = 1024;
189 struct roar_buffer * buffer;
190 void * data;
191 ssize_t ret;
192
193 if ( roar_buffer_new_data(&buffer, len, &data) == -1 )
194  return -1;
195
196 ret = roar_vio_read(self->input.vio, data, len);
197
198 if ( ret == -1 && roar_error == ROAR_ERROR_AGAIN ) {
199  ret = 0;
200 } else if ( ret < 1 ) {
201  roar_buffer_free(buffer);
202  if ( roar_error != ROAR_ERROR_AGAIN ) {
203   self->status = STATUS_DONE;
204   roar_vio_close(self->input.vio);
205  }
206  return 0;
207 }
208
209 if ( roar_buffer_set_len(buffer, ret) == -1 ) {
210  roar_buffer_free(buffer);
211  return -1;
212 }
213
214 if ( roar_buffer_moveintoqueue(obuffer, &buffer) == -1 ) {
215  roar_buffer_free(buffer);
216  return -1;
217 }
218
219 return 0;
220}
221
222static const struct resource_handle _g_resources[] = {
223 {
224  .uri = "/test/*",
225  .rawdata = "Hello world!\n",
226  .rawlen  = 13,
227  .content_type = NULL,
228  .header_send = NULL,
229  .body_send = NULL
230 },
231 {
232  .uri = "/szs/*",
233  .rawdata = NULL,
234  .rawlen  = -1,
235  .content_type = NULL,
236  .header_send = NULL,
237  .body_send = slow_zero_stream
238 },
239 {
240  .uri = "*",
241  .rawdata = NULL,
242  .rawlen  = -1,
243  .content_type = NULL,
244  .header_send = __res_vio_header_send,
245  .body_send = __res_vio_body_send
246 }
247};
248
249
250static inline int __ret(struct http_client * self, struct roar_buffer ** obuffer) {
251 ROAR_DBG("__ret(self=%p, obuffer=%p): self->status=%i", self, obuffer, (int)self->status);
252 if ( *obuffer != NULL )
253  return 0;
254 if ( self->status == STATUS_DONE )
255  return -1;
256 return 0;
257}
258
259static int __ctl(struct http_client * self, enum ctl_cmd cmd, void * argp) {
260 switch (cmd) {
261  case CMD_SET_CLIENTNAME:
262    if ( argp == NULL ) {
263     roar_err_set(ROAR_ERROR_FAULT);
264     return -1;
265    }
266    ROAR_DBG("__ctl(self=%p, cmd=%i, argp='%s') = ?", self, (int)cmd, (const char *)argp);
267    switch (__host.hosttype) {
268     case HOSTTYPE_GENERIC:
269       roar_err_set(ROAR_ERROR_BADHOST);
270       return -1;
271      break;
272     case HOSTTYPE_ROARD:
273       __host.hostspec.roard.clients_set_name(self->clientid, argp);
274      break;
275    }
276   break;
277 }
278
279 roar_err_set(ROAR_ERROR_BADRQC);
280 return -1;
281}
282
283static void __init(struct roar_dl_librarypara * para) {
284 // TODO add some init code here.
285
286 if ( para == NULL )
287  return;
288
289 if ( !roar_dl_para_check_version(para, "roard <0/RoarAudio>", "1.0beta8") ) {
290  __host.hosttype = HOSTTYPE_ROARD;
291  __host.hostspec.roard.clients_set_name = roar_dl_getsym(ROAR_DL_HANDLE_APPLICATION, "clients_set_name", -1);
292
293  // check if *all* function have been found:
294  if ( __host.hostspec.roard.clients_set_name == NULL ) {
295   __host.hosttype = HOSTTYPE_GENERIC;
296  }
297 }
298}
299
300// this function is a wrapper for __init() with the code which should be inlined.
301static inline void _init(struct roar_dl_librarypara * para) {
302 static int inited = 0;
303 if (inited) return;
304 __init(para);
305 inited = 1;
306}
307
308static const struct resource_handle * resource_lookup_by_uri(const char * uri) {
309 size_t i;
310
311 for (i = 0; i < (sizeof(_g_resources)/sizeof(*_g_resources)); i++) {
312  if ( !roar_mm_strselcmp(_g_resources[i].uri, uri) ) {
313   return &(_g_resources[i]);
314  }
315 }
316
317 roar_err_set(ROAR_ERROR_NOENT);
318 return NULL;
319}
320
321static int resource_header_send(struct http_client * self, struct roar_buffer ** obuffer) {
322 if ( self->resource->header_send != NULL )
323  return self->resource->header_send(self, obuffer);
324
325 return header_send(obuffer, 200, NULL, self->resource->content_type, self->resource->rawlen);
326}
327
328static int resource_body_send(struct http_client * self, struct roar_buffer ** obuffer) {
329 struct roar_buffer * buffer;
330 void * data;
331 int ret;
332
333 if ( self->resource->body_send != NULL )
334  return self->resource->body_send(self, obuffer);
335
336 if ( self->resource->rawlen == -1 ) {
337  self->status = STATUS_DONE;
338  roar_err_set(ROAR_ERROR_INVAL);
339  return -1;
340 }
341
342 if ( roar_buffer_new_data(&buffer, self->resource->rawlen, &data) == -1 ) {
343  self->status = STATUS_DONE;
344  return -1;
345 }
346
347 memcpy(data, self->resource->rawdata, self->resource->rawlen);
348
349 ret = roar_buffer_moveintoqueue(obuffer, &buffer);
350 self->status = STATUS_DONE;
351
352 return ret;
353}
354
355static int header_parse(struct http_client * self) {
356 void * data;
357 size_t len;
358 size_t i;
359 char * start, * end;
360 char * start_uri;
361 char * start_headers, * end_headers = NULL;
362 char * tmp;
363 struct roar_keyval * c;
364
365 if ( roar_buffer_get_datalen(self->input_buffer, &data, &len) == -1 )
366  return -1;
367
368 ROAR_DBG("header_parse(self=%p): data='%*s'", self, (int)len, data);
369
370 if ( len < 4 )
371  return 0;
372
373 for (i = 0; i < (len - 3); i++) {
374  if ( ((const char*)data)[i] == '\r' ) {
375   ROAR_DBG("header_parse(self=%p): i=%i", self, (int)i);
376   if ( !strncmp(data + i, "\r\n\r\n", 4) ) {
377    self->status = STATUS_END_OF_HEADER;
378    end_headers = data + i;
379    break;
380   }
381  }
382 }
383
384 if ( self->status != STATUS_END_OF_HEADER ) {
385  for (i = 0; i < (len - 1); i++) {
386   if ( ((const char*)data)[i] == '\n' ) {
387    ROAR_DBG("header_parse(self=%p): i=%i", self, (int)i);
388    if ( !strncmp(data + i, "\n\n", 2) ) {
389     self->status = STATUS_END_OF_HEADER;
390     end_headers = data + i;
391     break;
392    }
393   }
394  }
395 }
396
397 if ( self->status != STATUS_END_OF_HEADER )
398  return 0;
399
400 *end_headers = 0;
401
402 end = strstr(data, " ");
403 if ( end == NULL ) {
404  self->status = STATUS_BAD_HEADER;
405  return 1;
406 }
407
408 *end = 0;
409 end++;
410 self->method = roar_mm_strdup(data);
411
412 start = end;
413
414 end = strstr(start, " ");
415 if ( end == NULL ) {
416  self->status = STATUS_BAD_HEADER;
417  return 1;
418 }
419
420 *end = 0;
421 end++;
422 self->uri = roar_mm_strdup(start);
423 start_uri = start;
424
425 start = end;
426
427 end = strstr(start, "\r");
428 if ( end == NULL )
429  end = strstr(start, "\n");
430 if ( end == NULL ) {
431  self->status = STATUS_BAD_HEADER;
432  return 1;
433 }
434
435 *end = 0;
436 end++;
437 self->proto = roar_mm_strdup(start);
438
439 start_headers = end;
440
441 start = start_uri;
442
443 end = strstr(start, "?");
444 if ( end == NULL ) {
445  self->path = roar_mm_strdup(start);
446 } else {
447  *end = 0;
448  end++;
449  self->path = roar_mm_strdup(start);
450  self->query_string = roar_mm_strdup(end);
451 }
452
453 self->headerslen = 0;
454
455 i = end_headers - start_headers + 1;
456 self->headersstore = roar_mm_memdup(start_headers, i);
457 if ( self->headersstore == NULL ) {
458  self->status = STATUS_BAD_HEADER; // TODO: FIXME: not the right error, but works. ;)
459  return -1;
460 }
461
462 start_headers = self->headersstore;
463 end_headers   = start_headers + i;
464
465 for (tmp = start_headers; tmp < end_headers;) {
466  for (; tmp < end_headers && (*tmp == '\r' || *tmp == '\n'); tmp++);
467  if ( tmp == end_headers )
468   break;
469  self->headerslen++;
470  for (; tmp < end_headers && !(*tmp == '\r' || *tmp == '\n'); tmp++);
471 }
472
473 ROAR_DBG("header_parse(self=%p): self->headerslen=%i", self, (int)self->headerslen);
474
475 self->headers = roar_mm_malloc(sizeof(struct roar_keyval)*(self->headerslen+1));
476 if ( self->headers == NULL ) {
477  self->status = STATUS_BAD_HEADER; // TODO: FIXME: not the right error, but works. ;)
478  return -1;
479 }
480 memset(self->headers, 0, sizeof(struct roar_keyval)*(self->headerslen+1));
481 c = self->headers;
482
483 for (tmp = start_headers; tmp < end_headers;) {
484  ROAR_DBG("header_parse(self=%p): tmp='%s'", self, tmp);
485  for (; tmp < end_headers && (*tmp == '\r' || *tmp == '\n'); tmp++) *tmp = '\0';
486  if ( tmp == end_headers )
487   break;
488  ROAR_DBG("header_parse(self=%p): tmp='%s'", self, tmp);
489  c->key = tmp;
490  ROAR_DBG("header_parse(self=%p): c->key='%s'", self, c->key);
491  for (; tmp < end_headers && !(*tmp == '\r' || *tmp == '\n' || *tmp == ':'); tmp++);
492  c->value = tmp;
493  for (; tmp < end_headers && !(*tmp == '\r' || *tmp == '\n'); tmp++);
494  c++;
495 }
496
497 c->key = NULL;
498 c->value = NULL;
499
500 for (i = 0; i < (size_t)self->headerslen; i++) {
501  c = &(self->headers[i]);
502  if ( c->value[0] == '\0' ) {
503   c->value = NULL;
504   continue;
505  }
506
507  c->value[0] = '\0';
508  c->value++;
509
510  for (; c->value[0] == ' '; c->value++);
511
512  if ( c->value[0] == '\0' )
513   c->value = NULL;
514 }
515
516 return 1;
517}
518
519static int header_send(struct roar_buffer ** obuffer, int status, const char * msg, const char * content_type, ssize_t len) {
520 struct roar_buffer * buffer;
521 size_t bufferlen = 1024;
522 void * data;
523 char buffer_len[64];
524
525 if ( roar_buffer_new_data(&buffer, bufferlen, &data) == -1 )
526  return -1;
527
528 if ( msg == NULL ) {
529  switch (status) {
530   case 200: msg = "OK"; break;
531   case 400: msg = "Bad Request"; break;
532   case 404: msg = "File not found"; break;
533   case 500: msg = "Internal server error"; break;
534   default:  msg = "<<<unknown status code>>>"; break;
535  }
536 }
537
538 if ( content_type == NULL )
539  content_type = "text/plain";
540
541 if ( len == (ssize_t)-1 ) {
542  buffer_len[0] = 0;
543 } else {
544  snprintf(buffer_len, sizeof(buffer_len), "Content-Length: %lu\r\n", (long unsigned int)len);
545 }
546
547/*
548Date: Sun, 29 Jul 2012 01:08:15 GMT
549Cache-Control: no-cache,no-store
550Content-Type: text/html; charset=%s
551*/
552 snprintf(data, bufferlen, "HTTP/1.0 %i %s\r\n"
553                           "Server: protocol-http (libroar plugin)\r\n"
554                           "Connection: close\r\n"
555                           "Content-Type: %s\r\n"
556                           "%s"
557                           "\r\n",
558                           status, msg, content_type, buffer_len
559                           );
560
561 if ( roar_buffer_set_len(buffer, roar_mm_strlen(data)) == -1 ) {
562  roar_buffer_free(buffer);
563  return -1;
564 }
565
566 if ( roar_buffer_moveintoqueue(obuffer, &buffer) == -1 ) {
567  roar_buffer_free(buffer);
568  return -1;
569 }
570
571 return 0;
572}
573
574static void send_errorpage(struct http_client * self, struct roar_buffer ** obuffer, int error, const char * msg) {
575 struct roar_buffer * buffer;
576 const size_t bufferlen = 1024;
577 void * data;
578 int httperror;
579
580 if ( roar_err_convert(&httperror, ROAR_ERROR_TYPE_HTTP, error, ROAR_ERROR_TYPE_ROARAUDIO) == -1 )
581  httperror = 500;
582
583 if ( msg == NULL )
584  msg = roar_error2str(error);
585
586 // send header and mark as done early so we can just return in case some of the later calls fail.
587 header_send(obuffer, httperror, msg, "text/html", -1);
588 self->status = STATUS_DONE;
589
590 if ( roar_buffer_new_data(&buffer, bufferlen, &data) == -1 )
591  return;
592
593 snprintf(data, bufferlen, "<html>\n"
594                           " <head><title>%i - %s</title></head>\n"
595                           " <body>\n"
596                           "  <h1>%i - %s</h1><hr>\n"
597                           " </body>\n"
598                           "</html>",
599                           httperror, msg, httperror, msg);
600
601 _LIBROAR_IGNORE_RET(roar_buffer_set_len(buffer, roar_mm_strlen(data)));
602
603 if ( roar_buffer_moveintoqueue(obuffer, &buffer) == -1 )
604  roar_buffer_free(buffer);
605}
606
607static void handle_client(struct http_client * self, struct roar_buffer ** obuffer) {
608 struct roar_keyval * kv;
609
610 // meta stuff:
611 // try to set client name.
612 kv = roar_keyval_lookup(self->headers, "user-agent", self->headerslen, 0);
613 if ( kv != NULL && kv->value != NULL ) {
614  __ctl(self, CMD_SET_CLIENTNAME, kv->value);
615 }
616
617 // first try lookup including query string. if nothing is found
618 // retry search with only resource path.
619 self->resource = resource_lookup_by_uri(self->uri);
620 if ( self->resource == NULL )
621  self->resource = resource_lookup_by_uri(self->path);
622
623 if ( self->resource == NULL ) {
624  send_errorpage(self, obuffer, roar_error, NULL);
625  return;
626 }
627
628 if ( resource_header_send(self, obuffer) == -1 ) {
629  send_errorpage(self, obuffer, roar_error, NULL);
630  return;
631 }
632
633 resource_body_send(self, obuffer);
634
635 //send_errorpage(self, obuffer, ROAR_ERROR_CAUSALITY, NULL);
636// send_errorpage(self, obuffer, roar_random_uint16() % ROAR_ERROR_BADLICENSE, NULL);
637 return;
638}
639
640
641static int _set_proto(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * protopara, ssize_t protoparalen, struct roar_dl_librarypara * pluginpara) {
642 struct http_client * self = roar_mm_malloc(sizeof(struct http_client));
643
644 (void)vio, (void)protopara, (void)protoparalen;
645
646 if ( self == NULL )
647  return -1;
648
649 _init(pluginpara);
650
651 memset(self, 0, sizeof(*self));
652 self->status = STATUS_WAITING_FOR_HEADERS;
653 self->headerslen = (ssize_t)-1;
654 self->clientid = client;
655
656 if ( pluginpara != NULL ) {
657  roar_dl_para_ref(pluginpara);
658  self->pluginpara = pluginpara;
659 }
660
661 *userdata = self;
662
663 return __ret(self, obuffer);
664}
665
666static int _unset_proto(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * protopara, ssize_t protoparalen, struct roar_dl_librarypara * pluginpara) {
667 struct http_client * self = *userdata;
668
669 (void)client, (void)vio, (void)obuffer, (void)protopara, (void)protoparalen, (void)pluginpara;
670
671 if ( self->input_buffer != NULL )
672  roar_buffer_free(self->input_buffer);
673
674 if ( self->method != NULL )
675  roar_mm_free(self->method);
676 if ( self->proto != NULL )
677  roar_mm_free(self->proto);
678 if ( self->uri != NULL )
679  roar_mm_free(self->uri);
680 if ( self->path != NULL )
681  roar_mm_free(self->path);
682 if ( self->query_string != NULL )
683  roar_mm_free(self->query_string);
684 if ( self->headersstore != NULL )
685  roar_mm_free(self->headersstore);
686 if ( self->headers != NULL )
687  roar_mm_free(self->headers);
688
689 if ( self->pluginpara != NULL )
690  roar_dl_para_unref(self->pluginpara);
691
692 roar_mm_free(self);
693 *userdata = NULL;
694
695 return 0;
696}
697
698#define _INCREMENT 256
699static int _handle(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * protopara, ssize_t protoparalen, struct roar_dl_librarypara * pluginpara) {
700 struct http_client * self = *userdata;
701 void * data;
702 size_t oldlen;
703 ssize_t ret;
704
705 (void)client, (void)protopara, (void)protoparalen, (void)pluginpara;
706
707 if ( self->status != STATUS_WAITING_FOR_HEADERS )
708  return __ret(self, obuffer);
709
710 if ( self->input_buffer == NULL ) {
711  if ( roar_buffer_new_data(&(self->input_buffer), _INCREMENT, &data) == -1 )
712   return -1;
713  oldlen = 0;
714 } else {
715  if ( roar_buffer_get_len(self->input_buffer, &oldlen) == -1 )
716   return -1;
717  if ( roar_buffer_set_len(self->input_buffer, oldlen + _INCREMENT) == -1 )
718   return -1;
719  if ( roar_buffer_get_data(self->input_buffer, &data) == -1 )
720   return -1;
721 }
722
723 data += oldlen;
724
725 ret = roar_vio_read(vio, data, _INCREMENT);
726 if ( ret == (ssize_t)-1 ) {
727  // we can safely ignore return value here as we return error anyway.
728  _LIBROAR_IGNORE_RET(roar_buffer_set_len(self->input_buffer, oldlen));
729  return -1;
730 }
731
732 if ( roar_buffer_set_len(self->input_buffer, oldlen + ret) == -1 ) {
733  ROAR_WARN("_handle(*): Can not reset buffer length. BAD. Error was: %s", roar_errorstring);
734  return -1;
735 }
736
737 header_parse(self);
738
739 if ( self->status == STATUS_BAD_HEADER ) {
740  header_send(obuffer, 400, NULL, NULL, -1);
741  self->status = STATUS_DONE;
742 } else if ( self->status == STATUS_END_OF_HEADER ) {
743  handle_client(self, obuffer);
744 }
745
746 return __ret(self, obuffer);
747}
748
749// this is a dummy function only used to kill the client after all data has been flushed.
750static int _flushed(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * protopara, ssize_t protoparalen, struct roar_dl_librarypara * pluginpara) {
751 struct http_client * self = *userdata;
752
753 (void)client, (void)vio, (void)protopara, (void)protoparalen, (void)pluginpara;
754
755 if ( self->status == STATUS_RUNNING_DATA )
756  resource_body_send(self, obuffer);
757
758 return __ret(self, obuffer);
759}
760
761static const struct roar_dl_proto proto = {
762 .proto = ROAR_PROTO_HTTP,
763 .description = "Hyper Text Transfer Protocol",
764 .flags = ROAR_DL_PROTO_FLAGS_NONE,
765 .set_proto = _set_proto,
766 .unset_proto = _unset_proto,
767 .handle = _handle,
768 .flush = NULL,
769 .flushed = _flushed,
770 .status = NULL
771};
772
773static int __reg_proto(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib) {
774 (void)para, (void)lib;
775 ROAR_DL_PLUGIN_REG_FN(ROAR_DL_PROTO_SUBTYPE, proto, ROAR_DL_PROTO_VERSION);
776 return 0;
777}
778
779ROAR_DL_PLUGIN_START(protocol_http) {
780 ROAR_DL_PLUGIN_META_PRODUCT_NIV("protocol-http", ROAR_VID_ROARAUDIO, ROAR_VNAME_ROARAUDIO);
781 ROAR_DL_PLUGIN_META_VERSION(ROAR_VERSION_STRING);
782 ROAR_DL_PLUGIN_META_LICENSE_TAG(GPLv3_0);
783 ROAR_DL_PLUGIN_META_CONTACT_FLNE("Philipp", "Schafft", "ph3-der-loewe", "lion@lion.leolix.org");
784 ROAR_DL_PLUGIN_META_DESC("Implementation of the HTTP Protocol");
785
786 ROAR_DL_PLUGIN_REG(ROAR_DL_FN_PROTO, __reg_proto);
787} ROAR_DL_PLUGIN_END
788
789//ll
Note: See TracBrowser for help on using the repository browser.