OSDN Git Service

enable to specify IP address string for host argument.
[bbk/bchanf.git] / src / http / http_connector.c
1 /*
2  * http_connector.c
3  *
4  * Copyright (c) 2012-2015 project bchan
5  *
6  * This software is provided 'as-is', without any express or implied
7  * warranty. In no event will the authors be held liable for any damages
8  * arising from the use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not
15  *    claim that you wrote the original software. If you use this software
16  *    in a product, an acknowledgment in the product documentation would be
17  *    appreciated but is not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  *    misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source
23  *    distribution.
24  *
25  */
26
27 #include "http_connector.h"
28
29 #include        <basic.h>
30 #include        <bstdio.h>
31 #include        <bstdlib.h>
32 #include        <errcode.h>
33 #include        <btron/btron.h>
34 #include        <btron/bsocket.h>
35
36 #include    <coll/idtocb.h>
37 #include    "http_transport.h"
38 #include    "http_requestlinestream.h"
39 #include    "http_defaultheaderstream.h"
40 #include    "http_statuslineparser.h"
41 #include    "http_defaultheaderparser.h"
42 #include    "http_transferdecoder.h"
43 #include    "http_contentdecoder.h"
44
45 #ifdef BCHAN_CONFIG_DEBUG
46 # define DP(arg) printf arg
47 # define DP_ER(msg, err) printf("%s (%d/%x)\n", msg, err>>16, err)
48 #else
49 # define DP(arg) /**/
50 # define DP_ER(msg, err) /**/
51 #endif
52
53 #if 0
54 # define DP_STATE(state) printf("%s\n", state)
55 #else
56 # define DP_STATE(state) /**/
57 #endif
58
59 struct http_reqentry_t_ {
60         idtocb_entry_t base;
61         enum {
62                 NON_EXISTENT,
63                 WAITING_TRANSPORT,
64                 DETECTING_ERROR,
65                 SENDING_REQUEST,
66                 WAITING_RESPONSE,
67                 RECEIVING_RESPONSE,
68                 ABORTED_BY_TRANSPORT,
69                 COMPLETED,
70                 FAILED
71         } status;
72         enum {
73                 SEND_REQUEST_LINE,
74                 SEND_HEADER_MINE,
75                 SEND_HEADER_USER,
76                 SEND_MESSAGE_BODY,
77                 SEND_COMPLETED,
78         } snd_state;
79         enum {
80                 RECEIVE_STATUS_LINE,
81                 RECEIVE_HEADER,
82                 RECEIVE_HEADER_END,
83                 RECEIVE_MESSAGE_BODY,
84                 RECEIVE_MESSAGE_BODY_TRANSFERDECODE,
85                 RECEIVE_MESSAGE_BODY_CONTENTDECODE,
86                 RECEIVE_MESSAGE_END,
87                 RECEIVE_COMPLETED,
88         } rcv_state;
89         Bool aborted_by_user;
90         HTTP_METHOD method;
91         UB *host;
92         W host_len;
93         SOCKADDR addr;
94         ID transport;
95         struct {
96                 http_statuslineparser_t sl;
97                 http_defaultheaderparser_t dh;
98                 http_transferdecoder_t tc;
99                 http_contentdecoder_t cc;
100                 struct {
101                         http_transferdecoder_result *transfer_result;
102                         W transfer_result_len;
103                         W transfer_result_consumed;
104                         http_contentdecoder_result *content_result;
105                         W content_result_len;
106                         W content_result_consumed;
107                 } body;
108         } rcv_reader;
109 };
110 typedef struct http_reqentry_t_ http_reqentry_t;
111
112 LOCAL VOID http_reqentry_attachendpoint(http_reqentry_t *entry, http_transport_t *transport, ID endpoint)
113 {
114         http_transport_holdendpoint(transport, endpoint);
115         entry->status = SENDING_REQUEST;
116         entry->transport = endpoint;
117         return;
118 }
119
120 LOCAL VOID http_reqentry_detachendpoint(http_reqentry_t *entry, http_transport_t *transport, Bool transport_close)
121 {
122         http_transport_releaseendpoint(transport, entry->transport, transport_close);
123         entry->transport = -1;
124         return;
125 }
126
127 LOCAL W http_reqentry_initialize(http_reqentry_t *entry, UB *host, W host_len, UH port, HTTP_METHOD method)
128 {
129         W err;
130         B buf[HBUFLEN];
131         HOSTENT ent;
132         struct in_addr addr;
133         struct sockaddr_in *addr_in;
134
135         entry->host = malloc(sizeof(UB)*(host_len+1));
136         if (entry->host == NULL) {
137                 err = ER_NOMEM; /* TODO: detail error code */
138                 goto error_host;
139         }
140         memcpy(entry->host, host, host_len);
141         entry->host[host_len] = '\0';
142         entry->host_len = host_len;
143
144         err = inet_aton(host, &addr);
145         if (err == 0) {
146                 err = so_gethostbyname(entry->host, &ent, buf);
147                 if (err < 0) {
148                         goto error_gethostbyname;
149                 }
150                 addr.s_addr = *(unsigned int *)(ent.h_addr_list[0]);
151         }
152         addr_in = (struct sockaddr_in *)&(entry->addr);
153         addr_in->sin_family = AF_INET;
154         addr_in->sin_port = htons( port );
155         addr_in->sin_addr = addr;
156
157         entry->aborted_by_user = False;
158         entry->status = WAITING_TRANSPORT;
159         entry->snd_state = SEND_REQUEST_LINE;
160         entry->rcv_state = RECEIVE_STATUS_LINE;
161         entry->method = method;
162         entry->transport = -1;
163
164         http_statuslineparser_initialize(&entry->rcv_reader.sl);
165         http_defaultheaderparser_initialize(&entry->rcv_reader.dh);
166
167         return 0;
168
169 error_gethostbyname:
170         free(entry->host);
171 error_host:
172         entry->status = NON_EXISTENT;
173         return err;
174 }
175
176 LOCAL VOID http_reqentry_finalize(http_reqentry_t *entry)
177 {
178         switch (entry->rcv_state) {
179         case RECEIVE_MESSAGE_BODY:
180         case RECEIVE_MESSAGE_BODY_TRANSFERDECODE:
181         case RECEIVE_MESSAGE_BODY_CONTENTDECODE:
182         case RECEIVE_MESSAGE_END:
183                 http_contentdecoder_finalize(&entry->rcv_reader.cc);
184                 http_transferdecoder_finalize(&entry->rcv_reader.tc);
185                 break;
186         case RECEIVE_STATUS_LINE:
187         case RECEIVE_HEADER:
188         case RECEIVE_HEADER_END:
189         case RECEIVE_COMPLETED:
190                 break;
191         }
192         http_defaultheaderparser_finalize(&entry->rcv_reader.dh);
193         http_statuslineparser_finalize(&entry->rcv_reader.sl);
194         if (entry->host != NULL) {
195                 free(entry->host);
196         }
197 }
198
199 struct http_reqdict_t_ {
200         idtocb_t *base;
201         W entries;
202         http_reqentry_t entry[1];
203 };
204 typedef struct http_reqdict_t_ http_reqdict_t;
205
206 typedef struct {
207         idtocb_iterator_t base;
208 } http_recdictiterator_t;
209
210 LOCAL Bool http_reqdictiterator_next(http_recdictiterator_t *iter, http_reqentry_t **entry)
211 {
212         return idtocb_iterator_next(&iter->base, (idtocb_entry_t**)entry);
213 }
214
215 LOCAL VOID http_reqdictiterator_initialize(http_recdictiterator_t *iter, http_reqdict_t *dict)
216 {
217         idtocb_iterator_initialize(&iter->base, dict->base);
218 }
219
220 LOCAL VOID http_reqdictiterator_finalize(http_recdictiterator_t *iter)
221 {
222         idtocb_iterator_finalize(&iter->base);
223 }
224
225 LOCAL ID http_reqdict_allocate(http_reqdict_t *dict, UB *host, W host_len, UH port, HTTP_METHOD method)
226 {
227         ID id;
228         http_reqentry_t *cb;
229         W err;
230
231         id = idtocb_allocate(dict->base);
232         if (id < 0) {
233                 return id;
234         }
235         err = idtocb_getcontrolblock(dict->base, id, (idtocb_entry_t**)&cb);
236         if (err < 0) {
237                 idtocb_free(dict->base, id);
238                 return err;
239         }
240
241         err = http_reqentry_initialize(cb, host, host_len, port, method);
242         if (err < 0) {
243                 idtocb_free(dict->base, id);
244                 return err;
245         }
246
247         return id;
248 }
249
250 LOCAL http_reqentry_t* http_reqdict_getentrybyID(http_reqdict_t *dict, ID id)
251 {
252         http_reqentry_t *entry;
253         W err;
254
255         err = idtocb_getcontrolblock(dict->base, id, (idtocb_entry_t**)&entry);
256         if (err < 0) {
257                 return NULL;
258         }
259         return entry;
260 }
261
262 LOCAL VOID http_reqdict_free(http_reqdict_t *dict, ID id)
263 {
264         http_reqentry_t *entry;
265         W err;
266
267         err = idtocb_getcontrolblock(dict->base, id, (idtocb_entry_t**)&entry);
268         if (err < 0) {
269                 return;
270         }
271         http_reqentry_finalize(entry);
272         idtocb_free(dict->base, id);
273 }
274
275 LOCAL http_reqdict_t* http_reqdict_new(W max_entries)
276 {
277         http_reqdict_t *dict;
278
279         dict = (http_reqdict_t*)malloc(sizeof(http_reqdict_t));
280         if (dict == NULL) {
281                 return NULL;
282         }
283         dict->base = idtocb_new(sizeof(http_reqentry_t), max_entries);
284         if (dict->base == NULL) {
285                 free(dict);
286                 return NULL;
287         }
288         return dict;
289 }
290
291 LOCAL VOID http_reqdict_delete(http_reqdict_t *dict)
292 {
293         http_recdictiterator_t iter;
294         http_reqentry_t *entry;
295         Bool cont;
296
297         http_reqdictiterator_initialize(&iter, dict);
298         for (;;) {
299                 cont = http_reqdictiterator_next(&iter, &entry);
300                 if (cont == False) {
301                         break;
302                 }
303                 http_reqentry_finalize(entry);
304         }
305         http_reqdictiterator_finalize(&iter);
306
307         idtocb_delete(dict->base);
308         free(dict);
309 }
310
311 struct http_connector_t_ {
312         http_reqdict_t *dict;
313         http_transport_t *transport;
314         ID flg;
315         ID sem;
316 };
317
318 #define HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector) \
319         err = wai_sem((connector)->sem, T_FOREVER); \
320         if (err < 0) { \
321                 return err; \
322         }
323 #define HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_VOID(connector) \
324         err = wai_sem((connector)->sem, T_FOREVER); \
325         if (err < 0) { \
326                 return; \
327         }
328 #define HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector) \
329         sig_sem((connector)->sem); 
330
331 #define HTTP_CONNECTOR_FLAG_CREARMASK(flag) (~(flag))
332 #define HTTP_CONNECTOR_FLAG_REQUEST 0x00000001
333 #define HTTP_CONNECTOR_FLAG_EVENT   0x00000002
334 #define HTTP_CONNECTOR_FLAG_CLEARMASK_REQUEST HTTP_CONNECTOR_FLAG_CREARMASK(HTTP_CONNECTOR_FLAG_REQUEST)
335 #define HTTP_CONNECTOR_FLAG_CLEARMASK_EVENT HTTP_CONNECTOR_FLAG_CREARMASK(HTTP_CONNECTOR_FLAG_EVENT)
336
337 EXPORT ID http_connector_createendpoint(http_connector_t *connector, UB *host, W host_len, UH port, HTTP_METHOD method)
338 {
339         ID id;
340         W err;
341
342         HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
343         id = http_reqdict_allocate(connector->dict, host, host_len, port, method);
344         HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
345         if (id < 0) {
346                 DP_ER("http_reqdict_allocate", id);
347                 return id; /* TODO */
348         }
349
350         err = set_flg(connector->flg, HTTP_CONNECTOR_FLAG_REQUEST);
351         if (err < 0) {
352                 DP_ER("set_flg", err);
353                 http_reqdict_free(connector->dict, id);
354                 return err;
355         }
356
357         return id;
358 }
359
360 EXPORT VOID http_connector_deleteendpoint(http_connector_t *connector, ID endpoint)
361 {
362         http_reqentry_t *entry;
363         Bool transport_close = True;
364         W err;
365
366         HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_VOID(connector);
367
368         entry = http_reqdict_getentrybyID(connector->dict, endpoint);
369         if (entry == NULL) {
370                 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
371                 return;
372         }
373
374         switch (entry->status) {
375         case SENDING_REQUEST:
376                 if (entry->snd_state == SEND_REQUEST_LINE) {
377                         transport_close = False;
378                         break;
379                 }
380                 /* intentional */
381         case WAITING_RESPONSE:
382         case RECEIVING_RESPONSE:
383                 http_reqentry_detachendpoint(entry, connector->transport, transport_close);
384                 break;
385         case NON_EXISTENT:
386         case WAITING_TRANSPORT:
387         case DETECTING_ERROR:
388         case ABORTED_BY_TRANSPORT:
389         case COMPLETED:
390         case FAILED:
391         }
392
393         http_reqdict_free(connector->dict, endpoint);
394
395         HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
396 }
397
398 LOCAL W http_connector_searchwaiting(http_connector_t *connector)
399 {
400         W ret = 0;
401         http_reqentry_t *entry;
402         http_recdictiterator_t iter;
403         Bool cont, holded;
404         ID endpoint;
405
406         http_reqdictiterator_initialize(&iter, connector->dict);
407         for (;;) {
408                 cont = http_reqdictiterator_next(&iter, &entry);
409                 if (cont == False) {
410                         break;
411                 }
412                 if (entry->status == WAITING_TRANSPORT) {
413                         endpoint = http_transport_searchendpoint(connector->transport, &entry->addr);
414                         if ((endpoint & 0xFFFF0000) == ER_NOEXS) {
415                                 endpoint = http_transport_prepairendpoint(connector->transport, &entry->addr);
416                                 if (endpoint < 0) {
417                                         entry->status = DETECTING_ERROR;
418                                         ret++;
419                                         continue;
420                                 }
421                         } else if (endpoint < 0) {
422                                 continue;
423                         }
424                         http_transport_isholdedendpoint(connector->transport, endpoint, &holded);
425                         if (holded != False) {
426                                 continue;
427                         }
428                         http_reqentry_attachendpoint(entry, connector->transport, endpoint);
429                         ret++;
430                 }
431         }
432         http_reqdictiterator_finalize(&iter);
433
434         return ret;
435 }
436
437 LOCAL Bool http_connector_isexistwaiting(http_connector_t *connector)
438 {
439         http_reqentry_t *entry;
440         http_recdictiterator_t iter;
441         Bool cont, ret = False;
442
443         http_reqdictiterator_initialize(&iter, connector->dict);
444         for (;;) {
445                 cont = http_reqdictiterator_next(&iter, &entry);
446                 if (cont == False) {
447                         break;
448                 }
449                 if (entry->status == WAITING_TRANSPORT) {
450                         ret = True;
451                         break;
452                 } else if (entry->status == DETECTING_ERROR) {
453                         ret = True;
454                         break;
455                 } else if (entry->status == SENDING_REQUEST) {
456                         ret = True;
457                         break;
458                 } else if (entry->status == WAITING_RESPONSE) {
459                         ret = True;
460                         break;
461                 } else if (entry->status == RECEIVING_RESPONSE) {
462                         ret = True;
463                         break;
464                 }
465         }
466         http_reqdictiterator_finalize(&iter);
467
468         return ret;
469 }
470
471 LOCAL W http_connector_waitreceiving(http_connector_t *connector, TMOUT tmout)
472 {
473         W ret = 0;
474         http_reqentry_t *entry;
475         http_recdictiterator_t iter;
476         Bool cont, is_ready;
477
478         http_reqdictiterator_initialize(&iter, connector->dict);
479         for (;;) {
480                 cont = http_reqdictiterator_next(&iter, &entry);
481                 if (cont == False) {
482                         break;
483                 }
484                 if (entry->status == WAITING_RESPONSE) {
485                         http_transport_setwaitingreceive(connector->transport, entry->transport);
486                 }
487         }
488         http_reqdictiterator_finalize(&iter);
489
490         http_transport_waitreceive(connector->transport, tmout);
491
492         http_reqdictiterator_initialize(&iter, connector->dict);
493         for (;;) {
494                 cont = http_reqdictiterator_next(&iter, &entry);
495                 if (cont == False) {
496                         break;
497                 }
498                 if (entry->status == WAITING_RESPONSE) {
499                         http_transport_isreadready(connector->transport, entry->transport, &is_ready);
500                         if (is_ready != False) {
501                                 entry->status = RECEIVING_RESPONSE;
502                                 ret++;
503                         }
504                 }
505         }
506         http_reqdictiterator_finalize(&iter);
507
508         return ret;
509 }
510
511 EXPORT W http_connector_waitconnection(http_connector_t *connector, TMOUT tmout)
512 {
513         W err;
514         Bool evt = False, exist;
515
516         err = wai_flg(connector->flg, HTTP_CONNECTOR_FLAG_REQUEST, WF_AND|NOCLR, tmout);
517         if (err < 0) {
518                 return err;
519         }
520
521         HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
522         err = http_connector_searchwaiting(connector);
523         if (err < 0) {
524                 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
525                 return err;
526         }
527         if (err > 0) {
528                 evt = True;
529         }
530         http_transport_releaseunusedendpoint(connector->transport);
531
532         exist = http_connector_isexistwaiting(connector);
533         if (exist == False) {
534                 clr_flg(connector->flg, HTTP_CONNECTOR_FLAG_CLEARMASK_REQUEST);
535         }
536
537         err = http_connector_waitreceiving(connector, tmout);
538         HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
539         if (err < 0) {
540                 return err;
541         }
542         if (err > 0) {
543                 evt = True;
544         }
545
546         if (evt != False) {
547                 err = set_flg(connector->flg, HTTP_CONNECTOR_FLAG_EVENT);
548                 if (err < 0) {
549                         DP_ER("set_flg", err);
550                 }
551         }
552
553         return 0;
554 }
555
556 LOCAL W http_connector_rcv_status_line(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
557 {
558         http_statuslineparser_result result;
559         UB *bin;
560         W i, len, err;
561         Bool end = False;
562
563         err = http_transport_read(connector->transport, entry->transport, &bin, &len);
564         if (err < 0) {
565                 DP_ER("http_transport_read", err);
566                 return err;
567         }
568
569         for (i = 0; i < len; i++) {
570                 end = http_statuslineparser_inputchar(&entry->rcv_reader.sl, bin[i], &result);
571                 if (end != False) {
572                         i++;
573                         break;
574                 }
575         }
576
577         http_transport_consumereadbuffer(connector->transport, entry->transport, i);
578
579         if (end != False) {
580                 if (result.error != HTTP_STATUSLINEPARSER_ERROR_NONE) {
581                         return -1; /* TODO */
582                 }
583                 entry->rcv_state = RECEIVE_HEADER;
584                 event->endpoint = entry->base.id;
585                 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_STATUSLINE;
586                 event->data.receive_statusline.version = result.version;
587                 event->data.receive_statusline.statuscode = result.statuscode;
588                 return 1;
589         }
590
591         return 0;
592 }
593
594 LOCAL W http_connector_rcv_header(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
595 {
596         HTTP_DEFAULTHEADERPARSER_RESULT result;
597         UB *bin;
598         W i, len, err;
599         Bool end = False;
600
601         err = http_transport_read(connector->transport, entry->transport, &bin, &len);
602         if (err < 0) {
603                 DP_ER("http_transport_read", err);
604                 return err;
605         }
606
607         for (i = 0; i < len; i++) {
608                 http_defaultheaderparser_inputchar(&entry->rcv_reader.dh, bin[i], &result);
609                 if (result == HTTP_DEFAULTHEADERPARSER_RESULT_MESSAGE_HEADER_END) {
610                         end = True;
611                         i++;
612                         break;
613                 }
614         }
615
616         http_transport_consumereadbuffer(connector->transport, entry->transport, i);
617
618         if (end != False) {
619                 entry->rcv_state = RECEIVE_HEADER_END;
620         }
621
622         event->endpoint = entry->base.id;
623         event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_HEADER;
624         event->data.receive_header.bin = bin;
625         event->data.receive_header.len = i;
626
627         return 1;
628 }
629
630 LOCAL W http_connector_rcv_header_end(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
631 {
632         W err;
633         W content_length;
634         HTTP_TRANSFERCODING_TYPE transfer_coding;
635         HTTP_CONTENTCODING_VALUE content_coding;
636
637         entry->rcv_state = RECEIVE_MESSAGE_BODY;
638         event->endpoint = entry->base.id;
639         event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_HEADER_END;
640
641         content_length = http_defaultheaderparsr_contentlength(&entry->rcv_reader.dh);
642         transfer_coding = http_defaultheaderparsr_transferencoding(&entry->rcv_reader.dh);
643         content_coding = http_defaultheaderparsr_contentencoding(&entry->rcv_reader.dh);
644
645         http_transferdecoder_initialize(&entry->rcv_reader.tc, transfer_coding, content_length);
646         err = http_contentdecoder_initialize(&entry->rcv_reader.cc, content_coding);
647         if (err < 0) {
648                 return err;
649         }
650         entry->rcv_reader.body.transfer_result = NULL;
651         entry->rcv_reader.body.transfer_result_len = 0;
652         entry->rcv_reader.body.transfer_result_consumed = 0;
653         entry->rcv_reader.body.content_result = NULL;
654         entry->rcv_reader.body.content_result_len = 0;
655         entry->rcv_reader.body.content_result_consumed = 0;
656
657         return 1;
658 }
659
660 LOCAL W http_connector_rcv_message_body_contentdecode(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
661 {
662         W err;
663         http_contentdecoder_result *result;
664
665         if (entry->rcv_reader.body.content_result_consumed == entry->rcv_reader.body.content_result_len) {
666                 err = http_contentdecoder_outputdata(&entry->rcv_reader.cc, &entry->rcv_reader.body.content_result, &entry->rcv_reader.body.content_result_len);
667                 if (err < 0) {
668                         DP_ER("http_contentdecoder_outputdata", err);
669                         return err;
670                 }
671                 entry->rcv_reader.body.content_result_consumed = 0;
672                 if (entry->rcv_reader.body.content_result_len == 0) {
673                         return 0;
674                 }
675         }
676         result = entry->rcv_reader.body.content_result + entry->rcv_reader.body.content_result_consumed;
677         entry->rcv_reader.body.content_result_consumed++;
678         switch (result->type) {
679         case HTTP_CONTENTDECODER_RESULTTYPE_DATA:
680                 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_MESSAGEBODY;
681                 event->endpoint = entry->base.id;
682                 event->data.receive_messagebody.bin = result->data;
683                 event->data.receive_messagebody.len = result->len;
684                 return 1;
685         case HTTP_CONTENTDECODER_RESULTTYPE_NEED_INPUT:
686                 entry->rcv_state = RECEIVE_MESSAGE_BODY_TRANSFERDECODE;
687                 break;
688         case HTTP_CONTENTDECODER_RESULTTYPE_END:
689                 entry->rcv_state = RECEIVE_MESSAGE_END;
690                 break;
691         }
692
693         return 0;
694 }
695
696 LOCAL W http_connector_rcv_message_body_transferdecode(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
697 {
698         http_transferdecoder_result *result;
699         W err;
700
701         if (entry->rcv_reader.body.transfer_result_consumed == entry->rcv_reader.body.transfer_result_len) {
702                 entry->rcv_state = RECEIVE_MESSAGE_BODY;
703                 return 0;
704         }
705
706         result = entry->rcv_reader.body.transfer_result + entry->rcv_reader.body.transfer_result_consumed;
707         switch (result->type) {
708         case HTTP_TRANSFERDECODER_RESULTTYPE_DATA:
709                 err = http_contentdecoder_inputentitybody(&entry->rcv_reader.cc, result->data, result->len);
710                 break;
711         case HTTP_TRANSFERDECODER_RESULTTYPE_END:
712                 err = http_contentdecoder_inputendofdata(&entry->rcv_reader.cc);
713                 break;
714         default:
715                 err = 0;
716         }
717         entry->rcv_reader.body.transfer_result_consumed++;
718         if (err < 0) {
719                 DP_ER("http_contentdecoder_inputXXX", err);
720                 return err;
721         }
722         entry->rcv_state = RECEIVE_MESSAGE_BODY_CONTENTDECODE;
723
724         return http_connector_rcv_message_body_contentdecode(connector, entry, event);
725 }
726
727 LOCAL W http_connector_rcv_message_body(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
728 {
729         UB *bin;
730         W len, err;
731
732         err = http_transport_read(connector->transport, entry->transport, &bin, &len);
733         if (err < 0) {
734                 DP_ER("http_transport_read", err);
735                 return err;
736         }
737
738         len = http_transferdecoder_inputentitybody(&entry->rcv_reader.tc, bin, len, &entry->rcv_reader.body.transfer_result, &entry->rcv_reader.body.transfer_result_len);
739         entry->rcv_reader.body.transfer_result_consumed = 0;
740         http_transport_consumereadbuffer(connector->transport, entry->transport, len);
741
742         entry->rcv_state = RECEIVE_MESSAGE_BODY_TRANSFERDECODE;
743
744         return http_connector_rcv_message_body_transferdecode(connector, entry, event);
745 }
746
747 LOCAL W http_connector_rcv_message_end(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
748 {
749         Bool connection_closed;
750
751         http_contentdecoder_finalize(&entry->rcv_reader.cc);
752         http_transferdecoder_finalize(&entry->rcv_reader.tc);
753         connection_closed = http_defaultheaderparser_connectionclosed(&entry->rcv_reader.dh);
754
755         entry->status = COMPLETED;
756         entry->rcv_state = RECEIVE_COMPLETED;
757         event->endpoint = entry->base.id;
758         event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_MESSAGEBODY_END;
759
760         http_reqentry_detachendpoint(entry, connector->transport, connection_closed);
761
762         return 1;
763 }
764
765 LOCAL W http_connector_handleevent_receiving_response(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
766 {
767         W err = 0;
768
769         switch (entry->rcv_state) {
770         case RECEIVE_STATUS_LINE:
771                 DP_STATE("RECEIVE_STATUS_LINE");
772                 err = http_connector_rcv_status_line(connector, entry, event);
773                 break;
774         case RECEIVE_HEADER:
775                 DP_STATE("RECEIVE_RECEIVE_HEADER");
776                 err = http_connector_rcv_header(connector, entry, event);
777                 break;
778         case RECEIVE_HEADER_END:
779                 DP_STATE("RECEIVE_HEADER_END");
780                 err = http_connector_rcv_header_end(connector, entry, event);
781                 break;
782         case RECEIVE_MESSAGE_BODY:
783                 DP_STATE("RECEIVE_MESSAGE_BODY");
784                 err = http_connector_rcv_message_body(connector, entry, event);
785                 break;
786         case RECEIVE_MESSAGE_BODY_TRANSFERDECODE:
787                 DP_STATE("RECEIVE_MESSAGE_BODY_TRANSFERDECODE");
788                 err = http_connector_rcv_message_body_transferdecode(connector, entry, event);
789                 break;
790         case RECEIVE_MESSAGE_BODY_CONTENTDECODE:
791                 DP_STATE("RECEIVE_MESSAGE_BODY_CONTENTDECDE");
792                 err = http_connector_rcv_message_body_contentdecode(connector, entry, event);
793                 break;
794         case RECEIVE_MESSAGE_END:
795                 DP_STATE("RECEIVE_MESSAGE_END");
796                 err = http_connector_rcv_message_end(connector, entry, event);
797                 break;
798         case RECEIVE_COMPLETED:
799                 DP_STATE("RECEIVE_COMPLETED");
800                 err = 0;
801                 break;
802         }
803
804         return err;
805 }
806
807 /* TODO: devide event found and need loop for state transition */
808 EXPORT Bool http_connector_searcheventtarget(http_connector_t *connector, http_connector_event *event)
809 {
810         http_reqentry_t *entry;
811         http_recdictiterator_t iter;
812         Bool cont, found = False;
813         W err;
814
815         event->type = HTTP_CONNECTOR_EVENTTYPE_NONE;
816
817         http_reqdictiterator_initialize(&iter, connector->dict);
818         for (;;) {
819                 cont = http_reqdictiterator_next(&iter, &entry);
820                 if (cont == False) {
821                         break;
822                 }
823                 if (entry->status == SENDING_REQUEST) {
824                         event->type = HTTP_CONNECTOR_EVENTTYPE_SEND;
825                         event->endpoint = entry->base.id;
826                         found = True;
827                         break;
828                 }
829                 if (entry->status == DETECTING_ERROR) {
830                         event->type = HTTP_CONNECTOR_EVENTTYPE_ERROR;
831                         event->endpoint = entry->base.id;
832                         entry->status = FAILED;
833                         found = True;
834                         break;
835                 }
836                 if (entry->status == RECEIVING_RESPONSE) {
837                         err = http_connector_handleevent_receiving_response(connector, entry, event);
838                         if ((err < 0)&&((err & 0xFFFF0000) != EX_WOULDBLOCK)) {
839                                 event->type = HTTP_CONNECTOR_EVENTTYPE_ERROR;
840                                 event->endpoint = entry->base.id;
841                                 entry->status = ABORTED_BY_TRANSPORT;
842                                 http_reqentry_detachendpoint(entry, connector->transport, True);
843                                 found = True;
844                                 break;
845                         }
846                         found = True;
847                         if (err > 0) {
848                                 break;
849                         }
850                 }
851         }
852         http_reqdictiterator_finalize(&iter);
853
854         return found;
855 }
856
857 EXPORT W http_connector_getevent(http_connector_t *connector, http_connector_event *event)
858 {
859         W err;
860         Bool found;
861
862         err = wai_flg(connector->flg, HTTP_CONNECTOR_FLAG_EVENT, WF_AND|NOCLR, T_NOWAIT);
863         if ((err & 0xFFFF0000) == ER_NONE) {
864                 return err;
865         }
866         if (err < 0) {
867                 DP_ER("wai_flg", err);
868                 return err;
869         }
870         HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
871         found = http_connector_searcheventtarget(connector, event);
872         HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
873         if (found == False) {
874                 err = clr_flg(connector->flg, HTTP_CONNECTOR_FLAG_CLEARMASK_EVENT);
875                 if (err < 0) {
876                         DP_ER("clr_flg", err);
877                         return err;
878                 }
879                 return ER_NONE; /* TODO: detail error code */
880         }
881         if (event->type == HTTP_CONNECTOR_EVENTTYPE_NONE) {
882                 return ER_NONE; /* TODO: detail error code */
883         }
884         return 0;
885 }
886
887 #define HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, state, entry) \
888         (entry) = http_reqdict_getentrybyID((connector)->dict, (endpoint)); \
889         if ((entry) == NULL) { \
890                 return ER_NOEXS; /* TODO: detail error code */ \
891         } \
892         if ((entry)->status != SENDING_REQUEST) { \
893                 return ER_PAR; /* TODO: suitable error code */ \
894         } \
895         if ((entry)->snd_state != (state)) { \
896                 return ER_PAR; /* TODO: suitable error code */ \
897         } \
898
899 #define HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, state1, state2, entry) \
900         (entry) = http_reqdict_getentrybyID((connector)->dict, (endpoint)); \
901         if ((entry) == NULL) { \
902                 return ER_NOEXS; /* TODO: detail error code */ \
903         } \
904         if ((entry)->status != SENDING_REQUEST) { \
905                 return ER_PAR; /* TODO: suitable error code */ \
906         } \
907         if (((entry)->snd_state != (state1))&&((entry)->snd_state != (state2))) { \
908                 return ER_PAR; /* TODO: suitable error code */ \
909         } \
910
911 EXPORT W http_connector_sendrequestline(http_connector_t *connector, ID endpoint, UB *path, W path_len)
912 {
913         http_reqentry_t *entry;
914         http_requestlinestream_t reqline;
915         W err, len;
916         Bool cont;
917         CONST UB *str;
918
919         HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
920
921         HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_REQUEST_LINE, entry);
922
923         err = http_requestlinestream_initialize(&reqline, entry->method, path, path_len);
924         if (err < 0) {
925                 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
926                 return err;
927         }
928         for (;;) {
929                 cont = http_requestlinestream_make(&reqline, &str, &len);
930                 if (cont == False) {
931                         break;
932                 }
933                 err = http_transport_write(connector->transport, entry->transport, str, len);
934                 if (err < 0) {
935                         break;
936                 }
937         }
938         http_requestlinestream_finalize(&reqline);
939
940         if (err < 0) {
941                 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
942                 return err;
943         }
944
945         entry->snd_state = SEND_HEADER_MINE;
946
947         HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
948
949         return 0;
950 }
951
952 LOCAL W http_connector_writedefaultheader(http_connector_t *connector, ID transport, UB *host, W host_len)
953 {
954         http_defaultheaderstream_t defaultheader;
955         W err = 0, len;
956         Bool cont;
957         CONST UB *str;
958
959         http_defaultheaderstream_initialize(&defaultheader, host, host_len);
960         for (;;) {
961                 cont = http_defaultheaderstream_make(&defaultheader, &str, &len);
962                 if (cont == False) {
963                         break;
964                 }
965                 err = http_transport_write(connector->transport, transport, str, len);
966                 if (err < 0) {
967                         break;
968                 }
969         }
970         http_defaultheaderstream_finalize(&defaultheader);
971
972         return err;
973 }
974
975 EXPORT W http_connector_sendheader(http_connector_t *connector, ID endpoint, UB *p, W len)
976 {
977         http_reqentry_t *entry;
978         W err;
979
980         HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
981
982         HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, SEND_HEADER_MINE, SEND_HEADER_USER, entry);
983
984         if (entry->snd_state == SEND_HEADER_MINE) {
985                 err = http_connector_writedefaultheader(connector, entry->transport, entry->host, entry->host_len);
986                 if (err < 0) {
987                         HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
988                         return err;
989                 }
990                 entry->snd_state = SEND_HEADER_USER;
991         }
992
993         err = http_transport_write(connector->transport, entry->transport, p, len);
994
995         HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
996
997         return err;
998 }
999
1000 EXPORT W http_connector_sendheaderend(http_connector_t *connector, ID endpoint)
1001 {
1002         http_reqentry_t *entry;
1003         W err;
1004
1005         HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
1006
1007         HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, SEND_HEADER_MINE, SEND_HEADER_USER, entry);
1008
1009         if (entry->snd_state == SEND_HEADER_MINE) {
1010                 err = http_connector_writedefaultheader(connector, entry->transport, entry->host, entry->host_len);
1011                 if (err < 0) {
1012                         HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1013                         return err;
1014                 }
1015         }
1016         err = http_transport_write(connector->transport, entry->transport, "\r\n", 2);
1017         if (err < 0) {
1018                 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1019                 return err;
1020         }
1021
1022         entry->snd_state = SEND_MESSAGE_BODY;
1023
1024         HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1025
1026         return 0;
1027 }
1028
1029 EXPORT W http_connector_sendmessagebody(http_connector_t *connector, ID endpoint, UB *p, W len)
1030 {
1031         http_reqentry_t *entry;
1032         W err;
1033
1034         HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
1035
1036         HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_MESSAGE_BODY, entry);
1037
1038         err = http_transport_write(connector->transport, entry->transport, p, len);
1039         HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1040         if (err < 0) {
1041                 return err;
1042         }
1043
1044         return 0;
1045 }
1046
1047 EXPORT W http_connector_sendmessagebodyend(http_connector_t *connector, ID endpoint)
1048 {
1049         http_reqentry_t *entry;
1050         W err;
1051
1052         HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
1053
1054         HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_MESSAGE_BODY, entry);
1055
1056         entry->status = WAITING_RESPONSE;
1057
1058         HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1059
1060         return 0;
1061 }
1062
1063 EXPORT http_connector_t* http_connector_new()
1064 {
1065         http_connector_t *connector;
1066
1067         connector = (http_connector_t*)malloc(sizeof(http_connector_t));
1068         if (connector == NULL) {
1069                 DP_ER("malloc", 0);
1070                 return NULL;
1071         }
1072         connector->dict = http_reqdict_new(10/*tmp*/);
1073         if (connector->dict == NULL) {
1074                 DP_ER("http_recdict_new", 0);
1075                 goto error_http_reqdict;
1076         }
1077         connector->flg = cre_flg(0, DELEXIT);
1078         if (connector->flg < 0) {
1079                 DP_ER("cre_flg", connector->flg);
1080                 goto error_flg;
1081         }
1082         connector->sem = cre_sem(1, SEM_EXCL|DELEXIT);
1083         if (connector->sem < 0) {
1084                 DP_ER("cre_sem", connector->sem);
1085                 goto error_sem;
1086         }
1087         connector->transport = http_transport_new(10/*tmp*/);
1088         if (connector->transport == NULL) {
1089                 DP_ER("http_transport_new", -1);
1090                 goto error_transport;
1091         }
1092
1093         return connector;
1094
1095         http_transport_delete(connector->transport);
1096 error_transport:
1097         del_sem(connector->sem);
1098 error_sem:
1099         del_flg(connector->flg);
1100 error_flg:
1101         http_reqdict_delete(connector->dict);
1102 error_http_reqdict:
1103         free(connector);
1104         return NULL;
1105 }
1106
1107 EXPORT VOID http_connector_delete(http_connector_t *connector)
1108 {
1109         http_transport_delete(connector->transport);
1110         del_sem(connector->sem);
1111         del_flg(connector->flg);
1112         http_reqdict_delete(connector->dict);
1113         free(connector);
1114 }