OSDN Git Service

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