OSDN Git Service

add semaphore.
[bbk/bchanf.git] / src / http / http_connector.c
1 /*
2  * http_connector.c
3  *
4  * Copyright (c) 2012 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_FLAG_CREARMASK(flag) (~(flag))
312 #define HTTP_CONNECTOR_FLAG_REQUEST 0x00000001
313 #define HTTP_CONNECTOR_FLAG_EVENT   0x00000002
314 #define HTTP_CONNECTOR_FLAG_CLEARMASK_REQUEST HTTP_CONNECTOR_FLAG_CREARMASK(HTTP_CONNECTOR_FLAG_REQUEST)
315 #define HTTP_CONNECTOR_FLAG_CLEARMASK_EVENT HTTP_CONNECTOR_FLAG_CREARMASK(HTTP_CONNECTOR_FLAG_EVENT)
316
317 EXPORT ID http_connector_createendpoint(http_connector_t *connector, UB *host, W host_len, UH port, HTTP_METHOD method)
318 {
319         ID id;
320         W err;
321
322         err = wai_sem(connector->sem, T_FOREVER);
323         if (err < 0) {
324                 return err;
325         }
326         id = http_reqdict_allocate(connector->dict, host, host_len, port, method);
327         sig_sem(connector->sem);
328         if (id < 0) {
329                 DP_ER("http_reqdict_allocate", id);
330                 return id; /* TODO */
331         }
332
333         err = set_flg(connector->flg, HTTP_CONNECTOR_FLAG_REQUEST);
334         if (err < 0) {
335                 DP_ER("set_flg", err);
336                 http_reqdict_free(connector->dict, id);
337                 return err;
338         }
339
340         return id;
341 }
342
343 EXPORT VOID http_connector_deleteendpoint(http_connector_t *connector, ID endpoint)
344 {
345         http_reqentry_t *entry;
346         Bool transport_close = True;
347         W err;
348
349         err = wai_sem(connector->sem, T_FOREVER);
350         if (err < 0) {
351                 return;
352         }
353
354         entry = http_reqdict_getentrybyID(connector->dict, endpoint);
355         if (entry == NULL) {
356                 sig_sem(connector->sem);
357                 return;
358         }
359
360         switch (entry->status) {
361         case SENDING_REQUEST:
362                 if (entry->snd_state == SEND_REQUEST_LINE) {
363                         transport_close = False;
364                         break;
365                 }
366                 /* intentional */
367         case WAITING_RESPONSE:
368         case RECEIVING_RESPONSE:
369                 http_reqentry_detachendpoint(entry, connector->transport, transport_close);
370                 break;
371         case NON_EXISTENT:
372         case WAITING_TRANSPORT:
373         case ABORTED_BY_TRANSPORT:
374         case COMPLETED:
375         }
376
377         http_reqdict_free(connector->dict, endpoint);
378
379         sig_sem(connector->sem);
380 }
381
382 LOCAL W http_connector_searchwaiting(http_connector_t *connector)
383 {
384         W ret = 0;
385         http_reqentry_t *entry;
386         http_recdictiterator_t iter;
387         Bool cont, holded;
388         ID endpoint;
389
390         http_reqdictiterator_initialize(&iter, connector->dict);
391         for (;;) {
392                 cont = http_reqdictiterator_next(&iter, &entry);
393                 if (cont == False) {
394                         break;
395                 }
396                 if (entry->status == WAITING_TRANSPORT) {
397                         endpoint = http_transport_searchendpoint(connector->transport, &entry->addr);
398                         if ((endpoint & 0xFFFF0000) == ER_NOEXS) {
399                                 endpoint = http_transport_prepairendpoint(connector->transport, &entry->addr);
400                                 if (endpoint < 0) {
401                                         continue;
402                                 }
403                         } else if (endpoint < 0) {
404                                 continue;
405                         }
406                         http_transport_isholdedendpoint(connector->transport, endpoint, &holded);
407                         if (holded != False) {
408                                 continue;
409                         }
410                         http_reqentry_attachendpoint(entry, connector->transport, endpoint);
411                         ret++;
412                 }
413         }
414         http_reqdictiterator_finalize(&iter);
415
416         return ret;
417 }
418
419 LOCAL W http_connector_waitreceiving(http_connector_t *connector, TMOUT tmout)
420 {
421         W ret = 0;
422         http_reqentry_t *entry;
423         http_recdictiterator_t iter;
424         Bool cont, is_ready;
425
426         http_reqdictiterator_initialize(&iter, connector->dict);
427         for (;;) {
428                 cont = http_reqdictiterator_next(&iter, &entry);
429                 if (cont == False) {
430                         break;
431                 }
432                 if (entry->status == WAITING_RESPONSE) {
433                         http_transport_setwaitingreceive(connector->transport, entry->transport);
434                 }
435         }
436         http_reqdictiterator_finalize(&iter);
437
438         http_transport_waitreceive(connector->transport, tmout);
439
440         http_reqdictiterator_initialize(&iter, connector->dict);
441         for (;;) {
442                 cont = http_reqdictiterator_next(&iter, &entry);
443                 if (cont == False) {
444                         break;
445                 }
446                 if (entry->status == WAITING_RESPONSE) {
447                         http_transport_isreadready(connector->transport, entry->transport, &is_ready);
448                         if (is_ready != False) {
449                                 entry->status = RECEIVING_RESPONSE;
450                                 ret++;
451                         }
452                 }
453         }
454         http_reqdictiterator_finalize(&iter);
455
456         return ret;
457 }
458
459 EXPORT W http_connector_waitconnection(http_connector_t *connector, TMOUT tmout)
460 {
461         W err;
462         Bool evt = False;
463
464         err = wai_sem(connector->sem, tmout);
465         if (err < 0) {
466                 return err;
467         }
468         err = http_connector_searchwaiting(connector);
469         if (err < 0) {
470                 sig_sem(connector->sem);
471                 return err;
472         }
473         if (err > 0) {
474                 evt = True;
475         }
476         http_transport_releaseunusedendpoint(connector->transport);
477
478         err = http_connector_waitreceiving(connector, tmout);
479         sig_sem(connector->sem);
480         if (err < 0) {
481                 return err;
482         }
483         if (err > 0) {
484                 evt = True;
485         }
486
487         if (evt != False) {
488                 err = set_flg(connector->flg, HTTP_CONNECTOR_FLAG_EVENT);
489                 if (err < 0) {
490                         DP_ER("set_flg", err);
491                 }
492         }
493
494         return 0;
495 }
496
497 LOCAL W http_connector_rcv_status_line(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
498 {
499         http_statuslineparser_result result;
500         UB *bin;
501         W i, len, err;
502         Bool end = False;
503
504         err = http_transport_read(connector->transport, entry->transport, &bin, &len);
505         if (err < 0) {
506                 DP_ER("http_transport_read", err);
507                 return err;
508         }
509
510         for (i = 0; i < len; i++) {
511                 end = http_statuslineparser_inputchar(&entry->rcv_reader.sl, bin[i], &result);
512                 if (end != False) {
513                         i++;
514                         break;
515                 }
516         }
517
518         http_transport_consumereadbuffer(connector->transport, entry->transport, i);
519
520         if (end != False) {
521                 if (result.error != HTTP_STATUSLINEPARSER_ERROR_NONE) {
522                         return -1; /* TODO */
523                 }
524                 entry->rcv_state = RECEIVE_HEADER;
525                 event->endpoint = entry->base.id;
526                 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_STATUSLINE;
527                 event->data.receive_statusline.version = result.version;
528                 event->data.receive_statusline.statuscode = result.statuscode;
529                 return 1;
530         }
531
532         return 0;
533 }
534
535 LOCAL W http_connector_rcv_header(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
536 {
537         HTTP_DEFAULTHEADERPARSER_RESULT result;
538         UB *bin;
539         W i, len, err;
540         Bool end = False;
541
542         err = http_transport_read(connector->transport, entry->transport, &bin, &len);
543         if (err < 0) {
544                 DP_ER("http_transport_read", err);
545                 return err;
546         }
547
548         for (i = 0; i < len; i++) {
549                 http_defaultheaderparser_inputchar(&entry->rcv_reader.dh, bin[i], &result);
550                 if (result == HTTP_DEFAULTHEADERPARSER_RESULT_MESSAGE_HEADER_END) {
551                         end = True;
552                         i++;
553                         break;
554                 }
555         }
556
557         http_transport_consumereadbuffer(connector->transport, entry->transport, i);
558
559         if (end != False) {
560                 entry->rcv_state = RECEIVE_HEADER_END;
561         }
562
563         event->endpoint = entry->base.id;
564         event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_HEADER;
565         event->data.receive_header.bin = bin;
566         event->data.receive_header.len = i;
567
568         return 1;
569 }
570
571 LOCAL W http_connector_rcv_header_end(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
572 {
573         W err;
574         W content_length;
575         HTTP_TRANSFERCODING_TYPE transfer_coding;
576         HTTP_CONTENTCODING_VALUE content_coding;
577
578         entry->rcv_state = RECEIVE_MESSAGE_BODY;
579         event->endpoint = entry->base.id;
580         event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_HEADER_END;
581
582         content_length = http_defaultheaderparsr_contentlength(&entry->rcv_reader.dh);
583         transfer_coding = http_defaultheaderparsr_transferencoding(&entry->rcv_reader.dh);
584         content_coding = http_defaultheaderparsr_contentencoding(&entry->rcv_reader.dh);
585
586         http_transferdecoder_initialize(&entry->rcv_reader.tc, transfer_coding, content_length);
587         err = http_contentdecoder_initialize(&entry->rcv_reader.cc, content_coding);
588         if (err < 0) {
589                 return err;
590         }
591         entry->rcv_reader.body.transfer_result = NULL;
592         entry->rcv_reader.body.transfer_result_len = 0;
593         entry->rcv_reader.body.transfer_result_consumed = 0;
594         entry->rcv_reader.body.content_result = NULL;
595         entry->rcv_reader.body.content_result_len = 0;
596         entry->rcv_reader.body.content_result_consumed = 0;
597
598         return 1;
599 }
600
601 LOCAL W http_connector_rcv_message_body_contentdecode(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
602 {
603         W err;
604         http_contentdecoder_result *result;
605
606         if (entry->rcv_reader.body.content_result_consumed == entry->rcv_reader.body.content_result_len) {
607                 err = http_contentdecoder_outputdata(&entry->rcv_reader.cc, &entry->rcv_reader.body.content_result, &entry->rcv_reader.body.content_result_len);
608                 if (err < 0) {
609                         DP_ER("http_contentdecoder_outputdata", err);
610                         return err;
611                 }
612                 entry->rcv_reader.body.content_result_consumed = 0;
613         }
614         result = entry->rcv_reader.body.content_result + entry->rcv_reader.body.content_result_consumed;
615         entry->rcv_reader.body.content_result_consumed++;
616         switch (result->type) {
617         case HTTP_CONTENTDECODER_RESULTTYPE_DATA:
618                 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_MESSAGEBODY;
619                 event->endpoint = entry->base.id;
620                 event->data.receive_messagebody.bin = result->data;
621                 event->data.receive_messagebody.len = result->len;
622                 return 1;
623         case HTTP_CONTENTDECODER_RESULTTYPE_NEED_INPUT:
624                 entry->rcv_state = RECEIVE_MESSAGE_BODY_TRANSFERDECODE;
625                 break;
626         case HTTP_CONTENTDECODER_RESULTTYPE_END:
627                 entry->rcv_state = RECEIVE_MESSAGE_END;
628                 break;
629         }
630
631         return 0;
632 }
633
634 LOCAL W http_connector_rcv_message_body_transferdecode(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
635 {
636         http_transferdecoder_result *result;
637         W err;
638
639         if (entry->rcv_reader.body.transfer_result_consumed == entry->rcv_reader.body.transfer_result_len) {
640                 entry->rcv_state = RECEIVE_MESSAGE_BODY;
641                 return 0;
642         }
643
644         result = entry->rcv_reader.body.transfer_result + entry->rcv_reader.body.transfer_result_consumed;
645         switch (result->type) {
646         case HTTP_TRANSFERDECODER_RESULTTYPE_DATA:
647                 err = http_contentdecoder_inputentitybody(&entry->rcv_reader.cc, result->data, result->len);
648                 break;
649         case HTTP_TRANSFERDECODER_RESULTTYPE_END:
650                 err = http_contentdecoder_inputendofdata(&entry->rcv_reader.cc);
651                 break;
652         default:
653                 err = 0;
654         }
655         entry->rcv_reader.body.transfer_result_consumed++;
656         if (err < 0) {
657                 DP_ER("http_contentdecoder_inputXXX", err);
658                 return err;
659         }
660         entry->rcv_state = RECEIVE_MESSAGE_BODY_CONTENTDECODE;
661
662         return http_connector_rcv_message_body_contentdecode(connector, entry, event);
663 }
664
665 LOCAL W http_connector_rcv_message_body(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
666 {
667         UB *bin;
668         W len, err;
669
670         err = http_transport_read(connector->transport, entry->transport, &bin, &len);
671         if (err < 0) {
672                 DP_ER("http_transport_read", err);
673                 return err;
674         }
675
676         len = http_transferdecoder_inputentitybody(&entry->rcv_reader.tc, bin, len, &entry->rcv_reader.body.transfer_result, &entry->rcv_reader.body.transfer_result_len);
677         entry->rcv_reader.body.transfer_result_consumed = 0;
678         http_transport_consumereadbuffer(connector->transport, entry->transport, len);
679
680         entry->rcv_state = RECEIVE_MESSAGE_BODY_TRANSFERDECODE;
681
682         return http_connector_rcv_message_body_transferdecode(connector, entry, event);
683 }
684
685 LOCAL W http_connector_rcv_message_end(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
686 {
687         Bool connection_closed;
688
689         http_contentdecoder_finalize(&entry->rcv_reader.cc);
690         http_transferdecoder_finalize(&entry->rcv_reader.tc);
691         connection_closed = http_defaultheaderparser_connectionclosed(&entry->rcv_reader.dh);
692
693         entry->status = COMPLETED;
694         entry->rcv_state = RECEIVE_COMPLETED;
695         event->endpoint = entry->base.id;
696         event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_MESSAGEBODY_END;
697
698         http_reqentry_detachendpoint(entry, connector->transport, connection_closed);
699
700         return 1;
701 }
702
703 LOCAL W http_connector_handleevent_receiving_response(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
704 {
705         W err = 0;
706
707         switch (entry->rcv_state) {
708         case RECEIVE_STATUS_LINE:
709                 DP_STATE("RECEIVE_STATUS_LINE");
710                 err = http_connector_rcv_status_line(connector, entry, event);
711                 break;
712         case RECEIVE_HEADER:
713                 DP_STATE("RECEIVE_RECEIVE_HEADER");
714                 err = http_connector_rcv_header(connector, entry, event);
715                 break;
716         case RECEIVE_HEADER_END:
717                 DP_STATE("RECEIVE_HEADER_END");
718                 err = http_connector_rcv_header_end(connector, entry, event);
719                 break;
720         case RECEIVE_MESSAGE_BODY:
721                 DP_STATE("RECEIVE_MESSAGE_BODY");
722                 err = http_connector_rcv_message_body(connector, entry, event);
723                 break;
724         case RECEIVE_MESSAGE_BODY_TRANSFERDECODE:
725                 DP_STATE("RECEIVE_MESSAGE_BODY_TRANSFERDECODE");
726                 err = http_connector_rcv_message_body_transferdecode(connector, entry, event);
727                 break;
728         case RECEIVE_MESSAGE_BODY_CONTENTDECODE:
729                 DP_STATE("RECEIVE_MESSAGE_BODY_CONTENTDECDE");
730                 err = http_connector_rcv_message_body_contentdecode(connector, entry, event);
731                 break;
732         case RECEIVE_MESSAGE_END:
733                 DP_STATE("RECEIVE_MESSAGE_END");
734                 err = http_connector_rcv_message_end(connector, entry, event);
735                 break;
736         case RECEIVE_COMPLETED:
737                 DP_STATE("RECEIVE_COMPLETED");
738                 err = 0;
739                 break;
740         }
741
742         return err;
743 }
744
745 /* TODO: devide event found and need loop for state transition */
746 EXPORT Bool http_connector_searcheventtarget(http_connector_t *connector, http_connector_event *event)
747 {
748         http_reqentry_t *entry;
749         http_recdictiterator_t iter;
750         Bool cont, found = False;
751         W err;
752
753         event->type = HTTP_CONNECTOR_EVENTTYPE_NONE;
754
755         http_reqdictiterator_initialize(&iter, connector->dict);
756         for (;;) {
757                 cont = http_reqdictiterator_next(&iter, &entry);
758                 if (cont == False) {
759                         break;
760                 }
761                 if (entry->status == SENDING_REQUEST) {
762                         event->type = HTTP_CONNECTOR_EVENTTYPE_SEND;
763                         event->endpoint = entry->base.id;
764                         found = True;
765                         break;
766                 }
767                 if (entry->status == RECEIVING_RESPONSE) {
768                         err = http_connector_handleevent_receiving_response(connector, entry, event);
769                         if ((err < 0)&&((err & 0xFFFF0000) != EX_WOULDBLOCK)) {
770                                 event->type = HTTP_CONNECTOR_EVENTTYPE_ERROR;
771                                 event->endpoint = entry->base.id;
772                                 entry->status = ABORTED_BY_TRANSPORT;
773                                 http_reqentry_detachendpoint(entry, connector->transport, True);
774                                 break;
775                         }
776                         found = True;
777                         if (err > 0) {
778                                 break;
779                         }
780                 }
781         }
782         http_reqdictiterator_finalize(&iter);
783
784         return found;
785 }
786
787 EXPORT W http_connector_getevent(http_connector_t *connector, http_connector_event *event)
788 {
789         W err;
790         Bool found;
791
792         err = wai_flg(connector->flg, HTTP_CONNECTOR_FLAG_EVENT, WF_AND|NOCLR, T_NOWAIT);
793         if ((err & 0xFFFF0000) == ER_NONE) {
794                 return err;
795         }
796         if (err < 0) {
797                 DP_ER("wai_flg", err);
798                 return err;
799         }
800         err = wai_sem(connector->sem, T_FOREVER);
801         if (err < 0) {
802                 return err;
803         }
804         found = http_connector_searcheventtarget(connector, event);
805         sig_sem(connector->sem);
806         if (found == False) {
807                 err = clr_flg(connector->flg, HTTP_CONNECTOR_FLAG_CLEARMASK_EVENT);
808                 if (err < 0) {
809                         DP_ER("clr_flg", err);
810                         return err;
811                 }
812                 return ER_NONE; /* TODO: detail error code */
813         }
814         if (event->type == HTTP_CONNECTOR_EVENTTYPE_NONE) {
815                 return ER_NONE; /* TODO: detail error code */
816         }
817         return 0;
818 }
819
820 #define HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, state, entry) \
821         (entry) = http_reqdict_getentrybyID((connector)->dict, (endpoint)); \
822         if ((entry) == NULL) { \
823                 return ER_NOEXS; /* TODO: detail error code */ \
824         } \
825         if ((entry)->status != SENDING_REQUEST) { \
826                 return ER_PAR; /* TODO: suitable error code */ \
827         } \
828         if ((entry)->snd_state != (state)) { \
829                 return ER_PAR; /* TODO: suitable error code */ \
830         } \
831
832 #define HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, state1, state2, entry) \
833         (entry) = http_reqdict_getentrybyID((connector)->dict, (endpoint)); \
834         if ((entry) == NULL) { \
835                 return ER_NOEXS; /* TODO: detail error code */ \
836         } \
837         if ((entry)->status != SENDING_REQUEST) { \
838                 return ER_PAR; /* TODO: suitable error code */ \
839         } \
840         if (((entry)->snd_state != (state1))&&((entry)->snd_state != (state2))) { \
841                 return ER_PAR; /* TODO: suitable error code */ \
842         } \
843
844 EXPORT W http_connector_sendrequestline(http_connector_t *connector, ID endpoint, UB *path, W path_len)
845 {
846         http_reqentry_t *entry;
847         http_requestlinestream_t reqline;
848         W err, len;
849         Bool cont;
850         CONST UB *str;
851
852         err = wai_sem(connector->sem, T_FOREVER);
853         if (err < 0) {
854                 return err;
855         }
856
857         HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_REQUEST_LINE, entry);
858
859         err = http_requestlinestream_initialize(&reqline, entry->method, path, path_len);
860         if (err < 0) {
861                 sig_sem(connector->sem);
862                 return err;
863         }
864         for (;;) {
865                 cont = http_requestlinestream_make(&reqline, &str, &len);
866                 if (cont == False) {
867                         break;
868                 }
869                 err = http_transport_write(connector->transport, entry->transport, str, len);
870                 if (err < 0) {
871                         break;
872                 }
873         }
874         http_requestlinestream_finalize(&reqline);
875
876         if (err < 0) {
877                 sig_sem(connector->sem);
878                 return err;
879         }
880
881         entry->snd_state = SEND_HEADER_MINE;
882
883         sig_sem(connector->sem);
884
885         return 0;
886 }
887
888 LOCAL W http_connector_writedefaultheader(http_connector_t *connector, ID transport, UB *host, W host_len)
889 {
890         http_defaultheaderstream_t defaultheader;
891         W err = 0, len;
892         Bool cont;
893         CONST UB *str;
894
895         http_defaultheaderstream_initialize(&defaultheader, host, host_len);
896         for (;;) {
897                 cont = http_defaultheaderstream_make(&defaultheader, &str, &len);
898                 if (cont == False) {
899                         break;
900                 }
901                 err = http_transport_write(connector->transport, transport, str, len);
902                 if (err < 0) {
903                         break;
904                 }
905         }
906         http_defaultheaderstream_finalize(&defaultheader);
907
908         return err;
909 }
910
911 EXPORT W http_connector_sendheader(http_connector_t *connector, ID endpoint, UB *p, W len)
912 {
913         http_reqentry_t *entry;
914         W err;
915
916         err = wai_sem(connector->sem, T_FOREVER);
917         if (err < 0) {
918                 return err;
919         }
920
921         HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, SEND_HEADER_MINE, SEND_HEADER_USER, entry);
922
923         if (entry->snd_state == SEND_HEADER_MINE) {
924                 err = http_connector_writedefaultheader(connector, entry->transport, entry->host, entry->host_len);
925                 if (err < 0) {
926                         sig_sem(connector->sem);
927                         return err;
928                 }
929                 entry->snd_state = SEND_HEADER_USER;
930         }
931
932         sig_sem(connector->sem);
933
934         return 0;
935 }
936
937 EXPORT W http_connector_sendheaderend(http_connector_t *connector, ID endpoint)
938 {
939         http_reqentry_t *entry;
940         W err;
941
942         err = wai_sem(connector->sem, T_FOREVER);
943         if (err < 0) {
944                 return err;
945         }
946
947         HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, SEND_HEADER_MINE, SEND_HEADER_USER, entry);
948
949         if (entry->snd_state == SEND_HEADER_MINE) {
950                 err = http_connector_writedefaultheader(connector, entry->transport, entry->host, entry->host_len);
951                 if (err < 0) {
952                         sig_sem(connector->sem);
953                         return err;
954                 }
955         }
956         err = http_transport_write(connector->transport, entry->transport, "\r\n", 2);
957         if (err < 0) {
958                 sig_sem(connector->sem);
959                 return err;
960         }
961
962         entry->snd_state = SEND_MESSAGE_BODY;
963
964         sig_sem(connector->sem);
965
966         return 0;
967 }
968
969 EXPORT W http_connector_sendmessagebody(http_connector_t *connector, ID endpoint, UB *p, W len)
970 {
971         http_reqentry_t *entry;
972         W err;
973
974         err = wai_sem(connector->sem, T_FOREVER);
975         if (err < 0) {
976                 return err;
977         }
978
979         HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_MESSAGE_BODY, entry);
980
981         err = http_transport_write(connector->transport, entry->transport, p, len);
982         sig_sem(connector->sem);
983         if (err < 0) {
984                 return err;
985         }
986
987         return 0;
988 }
989
990 EXPORT W http_connector_sendmessagebodyend(http_connector_t *connector, ID endpoint)
991 {
992         http_reqentry_t *entry;
993         W err;
994
995         err = wai_sem(connector->sem, T_FOREVER);
996         if (err < 0) {
997                 return err;
998         }
999
1000         HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_MESSAGE_BODY, entry);
1001
1002         entry->status = WAITING_RESPONSE;
1003
1004         sig_sem(connector->sem);
1005
1006         return 0;
1007 }
1008
1009 EXPORT http_connector_t* http_connector_new()
1010 {
1011         http_connector_t *connector;
1012
1013         connector = (http_connector_t*)malloc(sizeof(http_connector_t));
1014         if (connector == NULL) {
1015                 DP_ER("malloc", 0);
1016                 return NULL;
1017         }
1018         connector->dict = http_reqdict_new(10/*tmp*/);
1019         if (connector->dict == NULL) {
1020                 DP_ER("http_recdict_new", 0);
1021                 goto error_http_reqdict;
1022         }
1023         connector->flg = cre_flg(0, DELEXIT);
1024         if (connector->flg < 0) {
1025                 DP_ER("cre_flg", connector->flg);
1026                 goto error_flg;
1027         }
1028         connector->sem = cre_sem(1, SEM_EXCL|DELEXIT);
1029         if (connector->sem < 0) {
1030                 DP_ER("cre_sem", connector->sem);
1031                 goto error_sem;
1032         }
1033         connector->transport = http_transport_new(10/*tmp*/);
1034         if (connector->transport == NULL) {
1035                 DP_ER("http_transport_new", -1);
1036                 goto error_transport;
1037         }
1038
1039         return connector;
1040
1041         http_transport_delete(connector->transport);
1042 error_transport:
1043         del_sem(connector->sem);
1044 error_sem:
1045         del_flg(connector->flg);
1046 error_flg:
1047         http_reqdict_delete(connector->dict);
1048 error_http_reqdict:
1049         free(connector);
1050         return NULL;
1051 }
1052
1053 EXPORT VOID http_connector_delete(http_connector_t *connector)
1054 {
1055         http_transport_delete(connector->transport);
1056         del_sem(connector->sem);
1057         del_flg(connector->flg);
1058         http_reqdict_delete(connector->dict);
1059         free(connector);
1060 }