OSDN Git Service

fix flag clear in not exist endpoint.
[bbk/bchanf.git] / src / http / http_connector.c
index d1f0ec8..d341dbb 100644 (file)
 #include       <btron/btron.h>
 #include       <btron/bsocket.h>
 
+#include    <coll/idtocb.h>
+#include    "http_transport.h"
+#include    "http_requestlinestream.h"
+#include    "http_defaultheaderstream.h"
+#include    "http_statuslineparser.h"
+#include    "http_defaultheaderparser.h"
+#include    "http_transferdecoder.h"
+#include    "http_contentdecoder.h"
+
 #ifdef BCHAN_CONFIG_DEBUG
 # define DP(arg) printf arg
 # define DP_ER(msg, err) printf("%s (%d/%x)\n", msg, err>>16, err)
 # define DP_ER(msg, err) /**/
 #endif
 
+#if 0
+# define DP_STATE(state) printf("%s\n", state)
+#else
+# define DP_STATE(state) /**/
+#endif
+
 struct http_reqentry_t_ {
+       idtocb_entry_t base;
        enum {
                NON_EXISTENT,
                WAITING_TRANSPORT,
@@ -56,37 +72,57 @@ struct http_reqentry_t_ {
                SEND_HEADER_MINE,
                SEND_HEADER_USER,
                SEND_MESSAGE_BODY,
+               SEND_COMPLETED,
        } snd_state;
        enum {
                RECEIVE_STATUS_LINE,
                RECEIVE_HEADER,
                RECEIVE_HEADER_END,
                RECEIVE_MESSAGE_BODY,
+               RECEIVE_MESSAGE_BODY_TRANSFERDECODE,
+               RECEIVE_MESSAGE_BODY_CONTENTDECODE,
                RECEIVE_MESSAGE_END,
+               RECEIVE_COMPLETED,
        } rcv_state;
        Bool aborted_by_user;
+       HTTP_METHOD method;
        UB *host;
        W host_len;
        SOCKADDR addr;
-       ID id;
+       ID transport;
+       struct {
+               http_statuslineparser_t sl;
+               http_defaultheaderparser_t dh;
+               http_transferdecoder_t tc;
+               http_contentdecoder_t cc;
+               struct {
+                       http_transferdecoder_result *transfer_result;
+                       W transfer_result_len;
+                       W transfer_result_consumed;
+                       http_contentdecoder_result *content_result;
+                       W content_result_len;
+                       W content_result_consumed;
+               } body;
+       } rcv_reader;
 };
 typedef struct http_reqentry_t_ http_reqentry_t;
 
-LOCAL VOID http_reqentry_attachendpoint(http_reqentry_t *entry)
+LOCAL VOID http_reqentry_attachendpoint(http_reqentry_t *entry, http_transport_t *transport, ID endpoint)
 {
+       http_transport_holdendpoint(transport, endpoint);
        entry->status = SENDING_REQUEST;
-       /* TODO */
+       entry->transport = endpoint;
        return;
 }
 
-LOCAL VOID http_reqentry_detachendpoint(http_reqentry_t *entry)
+LOCAL VOID http_reqentry_detachendpoint(http_reqentry_t *entry, http_transport_t *transport, Bool transport_close)
 {
-       entry->status = WAITING_TRANSPORT;
-       /* TODO */
+       http_transport_releaseendpoint(transport, entry->transport, transport_close);
+       entry->transport = -1;
        return;
 }
 
-LOCAL W http_reqentry_allocate(http_reqentry_t *entry, UB *host, W host_len, UH port, ID id)
+LOCAL W http_reqentry_initialize(http_reqentry_t *entry, UB *host, W host_len, UH port, HTTP_METHOD method)
 {
        W err;
        B buf[HBUFLEN];
@@ -115,7 +151,11 @@ LOCAL W http_reqentry_allocate(http_reqentry_t *entry, UB *host, W host_len, UH
        entry->status = WAITING_TRANSPORT;
        entry->snd_state = SEND_REQUEST_LINE;
        entry->rcv_state = RECEIVE_STATUS_LINE;
-       entry->id = id;
+       entry->method = method;
+       entry->transport = -1;
+
+       http_statuslineparser_initialize(&entry->rcv_reader.sl);
+       http_defaultheaderparser_initialize(&entry->rcv_reader.dh);
 
        return 0;
 
@@ -126,63 +166,87 @@ error_host:
        return err;
 }
 
-LOCAL VOID http_reqentry_free(http_reqentry_t *entry)
-{
-       entry->id = -1;
-       entry->host_len = 0;
-       if (entry->host != NULL) {
-               free(entry->host);
-       }
-       entry->status = NON_EXISTENT;
-}
-
-LOCAL VOID http_reqentry_initialize(http_reqentry_t *entry)
-{
-       entry->status = NON_EXISTENT;
-       entry->host = NULL;
-       entry->host_len = 0;
-       entry->id = -1;
-}
-
 LOCAL VOID http_reqentry_finalize(http_reqentry_t *entry)
 {
+       switch (entry->rcv_state) {
+       case RECEIVE_MESSAGE_BODY:
+       case RECEIVE_MESSAGE_BODY_TRANSFERDECODE:
+       case RECEIVE_MESSAGE_BODY_CONTENTDECODE:
+       case RECEIVE_MESSAGE_END:
+               http_contentdecoder_finalize(&entry->rcv_reader.cc);
+               http_transferdecoder_finalize(&entry->rcv_reader.tc);
+               break;
+       case RECEIVE_STATUS_LINE:
+       case RECEIVE_HEADER:
+       case RECEIVE_HEADER_END:
+       case RECEIVE_COMPLETED:
+               break;
+       }
+       http_defaultheaderparser_finalize(&entry->rcv_reader.dh);
+       http_statuslineparser_finalize(&entry->rcv_reader.sl);
        if (entry->host != NULL) {
                free(entry->host);
        }
 }
 
 struct http_reqdict_t_ {
+       idtocb_t *base;
        W entries;
        http_reqentry_t entry[1];
 };
 typedef struct http_reqdict_t_ http_reqdict_t;
 
-LOCAL ID http_reqdict_allocate(http_reqdict_t *dict, UB *host, W host_len, UH port)
+typedef struct {
+       idtocb_iterator_t base;
+} http_recdictiterator_t;
+
+LOCAL Bool http_reqdictiterator_next(http_recdictiterator_t *iter, http_reqentry_t **entry)
 {
-       W i, err;
+       return idtocb_iterator_next(&iter->base, (idtocb_entry_t**)entry);
+}
 
-       for (i = 0; i < dict->entries; i++) {
-               if (dict->entry[i].status == NON_EXISTENT) {
-                       break;
-               }
+LOCAL VOID http_reqdictiterator_initialize(http_recdictiterator_t *iter, http_reqdict_t *dict)
+{
+       idtocb_iterator_initialize(&iter->base, dict->base);
+}
+
+LOCAL VOID http_reqdictiterator_finalize(http_recdictiterator_t *iter)
+{
+       idtocb_iterator_finalize(&iter->base);
+}
+
+LOCAL ID http_reqdict_allocate(http_reqdict_t *dict, UB *host, W host_len, UH port, HTTP_METHOD method)
+{
+       ID id;
+       http_reqentry_t *cb;
+       W err;
+
+       id = idtocb_allocate(dict->base);
+       if (id < 0) {
+               return id;
        }
-       if (i == dict->entries) {
-               return ER_NOMEM; /* TODO: detail error code */
+       err = idtocb_getcontrolblock(dict->base, id, (idtocb_entry_t**)&cb);
+       if (err < 0) {
+               idtocb_free(dict->base, id);
+               return err;
        }
 
-       err = http_reqentry_allocate(dict->entry + i, host, host_len, port, i);
+       err = http_reqentry_initialize(cb, host, host_len, port, method);
        if (err < 0) {
+               idtocb_free(dict->base, id);
                return err;
        }
 
-       return i;
+       return id;
 }
 
 LOCAL http_reqentry_t* http_reqdict_getentrybyID(http_reqdict_t *dict, ID id)
 {
        http_reqentry_t *entry;
-       entry = dict->entry + id;
-       if (entry->status == NON_EXISTENT) {
+       W err;
+
+       err = idtocb_getcontrolblock(dict->base, id, (idtocb_entry_t**)&entry);
+       if (err < 0) {
                return NULL;
        }
        return entry;
@@ -191,86 +255,86 @@ LOCAL http_reqentry_t* http_reqdict_getentrybyID(http_reqdict_t *dict, ID id)
 LOCAL VOID http_reqdict_free(http_reqdict_t *dict, ID id)
 {
        http_reqentry_t *entry;
-       entry = http_reqdict_getentrybyID(dict, id);
-       if (entry == NULL) {
+       W err;
+
+       err = idtocb_getcontrolblock(dict->base, id, (idtocb_entry_t**)&entry);
+       if (err < 0) {
                return;
        }
-       http_reqentry_free(entry);
+       http_reqentry_finalize(entry);
+       idtocb_free(dict->base, id);
 }
 
 LOCAL http_reqdict_t* http_reqdict_new(W max_entries)
 {
        http_reqdict_t *dict;
-       W i;
 
-       dict = (http_reqdict_t*)malloc(sizeof(W)*sizeof(http_reqdict_t)*max_entries);
+       dict = (http_reqdict_t*)malloc(sizeof(http_reqdict_t));
        if (dict == NULL) {
                return NULL;
        }
-       dict->entries = max_entries;
-       for (i = 0; i < max_entries; i++) {
-               http_reqentry_initialize(dict->entry+i);
+       dict->base = idtocb_new(sizeof(http_reqentry_t), max_entries);
+       if (dict->base == NULL) {
+               free(dict);
+               return NULL;
        }
        return dict;
 }
 
 LOCAL VOID http_reqdict_delete(http_reqdict_t *dict)
 {
-       W i;
-       for (i = 0; i < dict->entries; i++) {
-               http_reqentry_finalize(dict->entry+i);
-       }
-       free(dict);
-}
-
-typedef struct {
-       http_reqdict_t *dict;
-       W i;
-} http_recdictiterator_t;
-
-LOCAL Bool http_reqdictiterator_next(http_recdictiterator_t *iter, http_reqentry_t **entry)
-{
-       http_reqentry_t *e0;
+       http_recdictiterator_t iter;
+       http_reqentry_t *entry;
+       Bool cont;
 
-       for (; iter->i < iter->dict->entries;) {
-               e0 = iter->dict->entry + iter->i;
-               iter->i++;
-               if (e0->status != NON_EXISTENT) {
-                       *entry = e0;
-                       return True;
+       http_reqdictiterator_initialize(&iter, dict);
+       for (;;) {
+               cont = http_reqdictiterator_next(&iter, &entry);
+               if (cont == False) {
+                       break;
                }
+               http_reqentry_finalize(entry);
        }
+       http_reqdictiterator_finalize(&iter);
 
-       return False;
-}
-
-LOCAL VOID http_reqdictiterator_initialize(http_recdictiterator_t *iter, http_reqdict_t *dict)
-{
-       iter->dict = dict;
-       iter->i = 0;
-}
-
-LOCAL VOID http_reqdictiterator_finalize(http_recdictiterator_t *iter)
-{
+       idtocb_delete(dict->base);
+       free(dict);
 }
 
 struct http_connector_t_ {
        http_reqdict_t *dict;
+       http_transport_t *transport;
        ID flg;
+       ID sem;
 };
 
+#define HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector) \
+       err = wai_sem((connector)->sem, T_FOREVER); \
+       if (err < 0) { \
+               return err; \
+       }
+#define HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_VOID(connector) \
+       err = wai_sem((connector)->sem, T_FOREVER); \
+       if (err < 0) { \
+               return; \
+       }
+#define HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector) \
+       sig_sem((connector)->sem); 
+
 #define HTTP_CONNECTOR_FLAG_CREARMASK(flag) (~(flag))
 #define HTTP_CONNECTOR_FLAG_REQUEST 0x00000001
 #define HTTP_CONNECTOR_FLAG_EVENT   0x00000002
 #define HTTP_CONNECTOR_FLAG_CLEARMASK_REQUEST HTTP_CONNECTOR_FLAG_CREARMASK(HTTP_CONNECTOR_FLAG_REQUEST)
 #define HTTP_CONNECTOR_FLAG_CLEARMASK_EVENT HTTP_CONNECTOR_FLAG_CREARMASK(HTTP_CONNECTOR_FLAG_EVENT)
 
-EXPORT ID http_connector_createendpoint(http_connector_t *connector, UB *host, W host_len, UH port)
+EXPORT ID http_connector_createendpoint(http_connector_t *connector, UB *host, W host_len, UH port, HTTP_METHOD method)
 {
        ID id;
        W err;
 
-       id = http_reqdict_allocate(connector->dict, host, host_len, port);
+       HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
+       id = http_reqdict_allocate(connector->dict, host, host_len, port, method);
+       HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
        if (id < 0) {
                DP_ER("http_reqdict_allocate", id);
                return id; /* TODO */
@@ -289,19 +353,46 @@ EXPORT ID http_connector_createendpoint(http_connector_t *connector, UB *host, W
 EXPORT VOID http_connector_deleteendpoint(http_connector_t *connector, ID endpoint)
 {
        http_reqentry_t *entry;
+       Bool transport_close = True;
+       W err;
+
+       HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_VOID(connector);
 
        entry = http_reqdict_getentrybyID(connector->dict, endpoint);
        if (entry == NULL) {
+               HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
                return;
        }
-       entry->aborted_by_user = True;
+
+       switch (entry->status) {
+       case SENDING_REQUEST:
+               if (entry->snd_state == SEND_REQUEST_LINE) {
+                       transport_close = False;
+                       break;
+               }
+               /* intentional */
+       case WAITING_RESPONSE:
+       case RECEIVING_RESPONSE:
+               http_reqentry_detachendpoint(entry, connector->transport, transport_close);
+               break;
+       case NON_EXISTENT:
+       case WAITING_TRANSPORT:
+       case ABORTED_BY_TRANSPORT:
+       case COMPLETED:
+       }
+
+       http_reqdict_free(connector->dict, endpoint);
+
+       HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
 }
 
-LOCAL VOID http_connector_collect(http_connector_t *connector)
+LOCAL W http_connector_searchwaiting(http_connector_t *connector)
 {
+       W ret = 0;
        http_reqentry_t *entry;
        http_recdictiterator_t iter;
-       Bool cont;
+       Bool cont, holded;
+       ID endpoint;
 
        http_reqdictiterator_initialize(&iter, connector->dict);
        for (;;) {
@@ -309,22 +400,34 @@ LOCAL VOID http_connector_collect(http_connector_t *connector)
                if (cont == False) {
                        break;
                }
-               if (entry->status == ABORTED_BY_TRANSPORT) {
-                       http_reqdict_free(connector->dict, entry->id);
-               } else if (entry->status == COMPLETED) {
-                       /* TODO: release transport endpoint */
-                       http_reqdict_free(connector->dict, entry->id);
+               if (entry->status == WAITING_TRANSPORT) {
+                       endpoint = http_transport_searchendpoint(connector->transport, &entry->addr);
+                       if ((endpoint & 0xFFFF0000) == ER_NOEXS) {
+                               endpoint = http_transport_prepairendpoint(connector->transport, &entry->addr);
+                               if (endpoint < 0) {
+                                       continue;
+                               }
+                       } else if (endpoint < 0) {
+                               continue;
+                       }
+                       http_transport_isholdedendpoint(connector->transport, endpoint, &holded);
+                       if (holded != False) {
+                               continue;
+                       }
+                       http_reqentry_attachendpoint(entry, connector->transport, endpoint);
+                       ret++;
                }
        }
        http_reqdictiterator_finalize(&iter);
+
+       return ret;
 }
 
-LOCAL W http_connector_searchwaiting(http_connector_t *connector)
+LOCAL Bool http_connector_isexistwaiting(http_connector_t *connector)
 {
-       W ret = 0;
        http_reqentry_t *entry;
        http_recdictiterator_t iter;
-       Bool cont;
+       Bool cont, ret = False;
 
        http_reqdictiterator_initialize(&iter, connector->dict);
        for (;;) {
@@ -333,10 +436,17 @@ LOCAL W http_connector_searchwaiting(http_connector_t *connector)
                        break;
                }
                if (entry->status == WAITING_TRANSPORT) {
-                       /* TODO: transport end point search */
-                       /* TODO: transport end point status change: HOLDED and sending */
-                       http_reqentry_attachendpoint(entry);
-                       ret++;
+                       ret = True;
+                       break;
+               } else if (entry->status == SENDING_REQUEST) {
+                       ret = True;
+                       break;
+               } else if (entry->status == WAITING_RESPONSE) {
+                       ret = True;
+                       break;
+               } else if (entry->status == RECEIVING_RESPONSE) {
+                       ret = True;
+                       break;
                }
        }
        http_reqdictiterator_finalize(&iter);
@@ -344,12 +454,12 @@ LOCAL W http_connector_searchwaiting(http_connector_t *connector)
        return ret;
 }
 
-LOCAL W http_connector_waitreceiving(http_connector_t *connector)
+LOCAL W http_connector_waitreceiving(http_connector_t *connector, TMOUT tmout)
 {
        W ret = 0;
        http_reqentry_t *entry;
        http_recdictiterator_t iter;
-       Bool cont;
+       Bool cont, is_ready;
 
        http_reqdictiterator_initialize(&iter, connector->dict);
        for (;;) {
@@ -358,10 +468,25 @@ LOCAL W http_connector_waitreceiving(http_connector_t *connector)
                        break;
                }
                if (entry->status == WAITING_RESPONSE) {
-                       /* TODO: end point status change: readinging */
-                       /* TODO: select() for end point */
-                       entry->status = RECEIVING_RESPONSE;
-                       ret++;
+                       http_transport_setwaitingreceive(connector->transport, entry->transport);
+               }
+       }
+       http_reqdictiterator_finalize(&iter);
+
+       http_transport_waitreceive(connector->transport, tmout);
+
+       http_reqdictiterator_initialize(&iter, connector->dict);
+       for (;;) {
+               cont = http_reqdictiterator_next(&iter, &entry);
+               if (cont == False) {
+                       break;
+               }
+               if (entry->status == WAITING_RESPONSE) {
+                       http_transport_isreadready(connector->transport, entry->transport, &is_ready);
+                       if (is_ready != False) {
+                               entry->status = RECEIVING_RESPONSE;
+                               ret++;
+                       }
                }
        }
        http_reqdictiterator_finalize(&iter);
@@ -372,20 +497,31 @@ LOCAL W http_connector_waitreceiving(http_connector_t *connector)
 EXPORT W http_connector_waitconnection(http_connector_t *connector, TMOUT tmout)
 {
        W err;
-       Bool evt = False;
+       Bool evt = False, exist;
 
-       /**/
-       http_connector_collect(connector);
+       err = wai_flg(connector->flg, HTTP_CONNECTOR_FLAG_REQUEST, WF_AND|NOCLR, tmout);
+       if (err < 0) {
+               return err;
+       }
 
+       HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
        err = http_connector_searchwaiting(connector);
        if (err < 0) {
+               HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
                return err;
        }
        if (err > 0) {
                evt = True;
        }
+       http_transport_releaseunusedendpoint(connector->transport);
 
-       err = http_connector_waitreceiving(connector);
+       exist = http_connector_isexistwaiting(connector);
+       if (exist == False) {
+               clr_flg(connector->flg, HTTP_CONNECTOR_FLAG_CLEARMASK_REQUEST);
+       }
+
+       err = http_connector_waitreceiving(connector, tmout);
+       HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
        if (err < 0) {
                return err;
        }
@@ -403,11 +539,263 @@ EXPORT W http_connector_waitconnection(http_connector_t *connector, TMOUT tmout)
        return 0;
 }
 
+LOCAL W http_connector_rcv_status_line(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
+{
+       http_statuslineparser_result result;
+       UB *bin;
+       W i, len, err;
+       Bool end = False;
+
+       err = http_transport_read(connector->transport, entry->transport, &bin, &len);
+       if (err < 0) {
+               DP_ER("http_transport_read", err);
+               return err;
+       }
+
+       for (i = 0; i < len; i++) {
+               end = http_statuslineparser_inputchar(&entry->rcv_reader.sl, bin[i], &result);
+               if (end != False) {
+                       i++;
+                       break;
+               }
+       }
+
+       http_transport_consumereadbuffer(connector->transport, entry->transport, i);
+
+       if (end != False) {
+               if (result.error != HTTP_STATUSLINEPARSER_ERROR_NONE) {
+                       return -1; /* TODO */
+               }
+               entry->rcv_state = RECEIVE_HEADER;
+               event->endpoint = entry->base.id;
+               event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_STATUSLINE;
+               event->data.receive_statusline.version = result.version;
+               event->data.receive_statusline.statuscode = result.statuscode;
+               return 1;
+       }
+
+       return 0;
+}
+
+LOCAL W http_connector_rcv_header(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
+{
+       HTTP_DEFAULTHEADERPARSER_RESULT result;
+       UB *bin;
+       W i, len, err;
+       Bool end = False;
+
+       err = http_transport_read(connector->transport, entry->transport, &bin, &len);
+       if (err < 0) {
+               DP_ER("http_transport_read", err);
+               return err;
+       }
+
+       for (i = 0; i < len; i++) {
+               http_defaultheaderparser_inputchar(&entry->rcv_reader.dh, bin[i], &result);
+               if (result == HTTP_DEFAULTHEADERPARSER_RESULT_MESSAGE_HEADER_END) {
+                       end = True;
+                       i++;
+                       break;
+               }
+       }
+
+       http_transport_consumereadbuffer(connector->transport, entry->transport, i);
+
+       if (end != False) {
+               entry->rcv_state = RECEIVE_HEADER_END;
+       }
+
+       event->endpoint = entry->base.id;
+       event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_HEADER;
+       event->data.receive_header.bin = bin;
+       event->data.receive_header.len = i;
+
+       return 1;
+}
+
+LOCAL W http_connector_rcv_header_end(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
+{
+       W err;
+       W content_length;
+       HTTP_TRANSFERCODING_TYPE transfer_coding;
+       HTTP_CONTENTCODING_VALUE content_coding;
+
+       entry->rcv_state = RECEIVE_MESSAGE_BODY;
+       event->endpoint = entry->base.id;
+       event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_HEADER_END;
+
+       content_length = http_defaultheaderparsr_contentlength(&entry->rcv_reader.dh);
+       transfer_coding = http_defaultheaderparsr_transferencoding(&entry->rcv_reader.dh);
+       content_coding = http_defaultheaderparsr_contentencoding(&entry->rcv_reader.dh);
+
+       http_transferdecoder_initialize(&entry->rcv_reader.tc, transfer_coding, content_length);
+       err = http_contentdecoder_initialize(&entry->rcv_reader.cc, content_coding);
+       if (err < 0) {
+               return err;
+       }
+       entry->rcv_reader.body.transfer_result = NULL;
+       entry->rcv_reader.body.transfer_result_len = 0;
+       entry->rcv_reader.body.transfer_result_consumed = 0;
+       entry->rcv_reader.body.content_result = NULL;
+       entry->rcv_reader.body.content_result_len = 0;
+       entry->rcv_reader.body.content_result_consumed = 0;
+
+       return 1;
+}
+
+LOCAL W http_connector_rcv_message_body_contentdecode(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
+{
+       W err;
+       http_contentdecoder_result *result;
+
+       if (entry->rcv_reader.body.content_result_consumed == entry->rcv_reader.body.content_result_len) {
+               err = http_contentdecoder_outputdata(&entry->rcv_reader.cc, &entry->rcv_reader.body.content_result, &entry->rcv_reader.body.content_result_len);
+               if (err < 0) {
+                       DP_ER("http_contentdecoder_outputdata", err);
+                       return err;
+               }
+               entry->rcv_reader.body.content_result_consumed = 0;
+       }
+       result = entry->rcv_reader.body.content_result + entry->rcv_reader.body.content_result_consumed;
+       entry->rcv_reader.body.content_result_consumed++;
+       switch (result->type) {
+       case HTTP_CONTENTDECODER_RESULTTYPE_DATA:
+               event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_MESSAGEBODY;
+               event->endpoint = entry->base.id;
+               event->data.receive_messagebody.bin = result->data;
+               event->data.receive_messagebody.len = result->len;
+               return 1;
+       case HTTP_CONTENTDECODER_RESULTTYPE_NEED_INPUT:
+               entry->rcv_state = RECEIVE_MESSAGE_BODY_TRANSFERDECODE;
+               break;
+       case HTTP_CONTENTDECODER_RESULTTYPE_END:
+               entry->rcv_state = RECEIVE_MESSAGE_END;
+               break;
+       }
+
+       return 0;
+}
+
+LOCAL W http_connector_rcv_message_body_transferdecode(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
+{
+       http_transferdecoder_result *result;
+       W err;
+
+       if (entry->rcv_reader.body.transfer_result_consumed == entry->rcv_reader.body.transfer_result_len) {
+               entry->rcv_state = RECEIVE_MESSAGE_BODY;
+               return 0;
+       }
+
+       result = entry->rcv_reader.body.transfer_result + entry->rcv_reader.body.transfer_result_consumed;
+       switch (result->type) {
+       case HTTP_TRANSFERDECODER_RESULTTYPE_DATA:
+               err = http_contentdecoder_inputentitybody(&entry->rcv_reader.cc, result->data, result->len);
+               break;
+       case HTTP_TRANSFERDECODER_RESULTTYPE_END:
+               err = http_contentdecoder_inputendofdata(&entry->rcv_reader.cc);
+               break;
+       default:
+               err = 0;
+       }
+       entry->rcv_reader.body.transfer_result_consumed++;
+       if (err < 0) {
+               DP_ER("http_contentdecoder_inputXXX", err);
+               return err;
+       }
+       entry->rcv_state = RECEIVE_MESSAGE_BODY_CONTENTDECODE;
+
+       return http_connector_rcv_message_body_contentdecode(connector, entry, event);
+}
+
+LOCAL W http_connector_rcv_message_body(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
+{
+       UB *bin;
+       W len, err;
+
+       err = http_transport_read(connector->transport, entry->transport, &bin, &len);
+       if (err < 0) {
+               DP_ER("http_transport_read", err);
+               return err;
+       }
+
+       len = http_transferdecoder_inputentitybody(&entry->rcv_reader.tc, bin, len, &entry->rcv_reader.body.transfer_result, &entry->rcv_reader.body.transfer_result_len);
+       entry->rcv_reader.body.transfer_result_consumed = 0;
+       http_transport_consumereadbuffer(connector->transport, entry->transport, len);
+
+       entry->rcv_state = RECEIVE_MESSAGE_BODY_TRANSFERDECODE;
+
+       return http_connector_rcv_message_body_transferdecode(connector, entry, event);
+}
+
+LOCAL W http_connector_rcv_message_end(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
+{
+       Bool connection_closed;
+
+       http_contentdecoder_finalize(&entry->rcv_reader.cc);
+       http_transferdecoder_finalize(&entry->rcv_reader.tc);
+       connection_closed = http_defaultheaderparser_connectionclosed(&entry->rcv_reader.dh);
+
+       entry->status = COMPLETED;
+       entry->rcv_state = RECEIVE_COMPLETED;
+       event->endpoint = entry->base.id;
+       event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_MESSAGEBODY_END;
+
+       http_reqentry_detachendpoint(entry, connector->transport, connection_closed);
+
+       return 1;
+}
+
+LOCAL W http_connector_handleevent_receiving_response(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
+{
+       W err = 0;
+
+       switch (entry->rcv_state) {
+       case RECEIVE_STATUS_LINE:
+               DP_STATE("RECEIVE_STATUS_LINE");
+               err = http_connector_rcv_status_line(connector, entry, event);
+               break;
+       case RECEIVE_HEADER:
+               DP_STATE("RECEIVE_RECEIVE_HEADER");
+               err = http_connector_rcv_header(connector, entry, event);
+               break;
+       case RECEIVE_HEADER_END:
+               DP_STATE("RECEIVE_HEADER_END");
+               err = http_connector_rcv_header_end(connector, entry, event);
+               break;
+       case RECEIVE_MESSAGE_BODY:
+               DP_STATE("RECEIVE_MESSAGE_BODY");
+               err = http_connector_rcv_message_body(connector, entry, event);
+               break;
+       case RECEIVE_MESSAGE_BODY_TRANSFERDECODE:
+               DP_STATE("RECEIVE_MESSAGE_BODY_TRANSFERDECODE");
+               err = http_connector_rcv_message_body_transferdecode(connector, entry, event);
+               break;
+       case RECEIVE_MESSAGE_BODY_CONTENTDECODE:
+               DP_STATE("RECEIVE_MESSAGE_BODY_CONTENTDECDE");
+               err = http_connector_rcv_message_body_contentdecode(connector, entry, event);
+               break;
+       case RECEIVE_MESSAGE_END:
+               DP_STATE("RECEIVE_MESSAGE_END");
+               err = http_connector_rcv_message_end(connector, entry, event);
+               break;
+       case RECEIVE_COMPLETED:
+               DP_STATE("RECEIVE_COMPLETED");
+               err = 0;
+               break;
+       }
+
+       return err;
+}
+
+/* TODO: devide event found and need loop for state transition */
 EXPORT Bool http_connector_searcheventtarget(http_connector_t *connector, http_connector_event *event)
 {
        http_reqentry_t *entry;
        http_recdictiterator_t iter;
        Bool cont, found = False;
+       W err;
+
+       event->type = HTTP_CONNECTOR_EVENTTYPE_NONE;
 
        http_reqdictiterator_initialize(&iter, connector->dict);
        for (;;) {
@@ -417,16 +805,23 @@ EXPORT Bool http_connector_searcheventtarget(http_connector_t *connector, http_c
                }
                if (entry->status == SENDING_REQUEST) {
                        event->type = HTTP_CONNECTOR_EVENTTYPE_SEND;
-                       event->endpoint = entry->id;
+                       event->endpoint = entry->base.id;
                        found = True;
                        break;
                }
                if (entry->status == RECEIVING_RESPONSE) {
-                       event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_MESSAGEBODY_END;
-                       event->endpoint = entry->id;
-                       entry->status = COMPLETED;
+                       err = http_connector_handleevent_receiving_response(connector, entry, event);
+                       if ((err < 0)&&((err & 0xFFFF0000) != EX_WOULDBLOCK)) {
+                               event->type = HTTP_CONNECTOR_EVENTTYPE_ERROR;
+                               event->endpoint = entry->base.id;
+                               entry->status = ABORTED_BY_TRANSPORT;
+                               http_reqentry_detachendpoint(entry, connector->transport, True);
+                               break;
+                       }
                        found = True;
-                       break;
+                       if (err > 0) {
+                               break;
+                       }
                }
        }
        http_reqdictiterator_finalize(&iter);
@@ -439,7 +834,7 @@ EXPORT W http_connector_getevent(http_connector_t *connector, http_connector_eve
        W err;
        Bool found;
 
-       err = wai_flg(connector->flg, HTTP_CONNECTOR_FLAG_EVENT, WF_AND, T_NOWAIT);
+       err = wai_flg(connector->flg, HTTP_CONNECTOR_FLAG_EVENT, WF_AND|NOCLR, T_NOWAIT);
        if ((err & 0xFFFF0000) == ER_NONE) {
                return err;
        }
@@ -447,7 +842,9 @@ EXPORT W http_connector_getevent(http_connector_t *connector, http_connector_eve
                DP_ER("wai_flg", err);
                return err;
        }
+       HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
        found = http_connector_searcheventtarget(connector, event);
+       HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
        if (found == False) {
                err = clr_flg(connector->flg, HTTP_CONNECTOR_FLAG_CLEARMASK_EVENT);
                if (err < 0) {
@@ -456,6 +853,9 @@ EXPORT W http_connector_getevent(http_connector_t *connector, http_connector_eve
                }
                return ER_NONE; /* TODO: detail error code */
        }
+       if (event->type == HTTP_CONNECTOR_EVENTTYPE_NONE) {
+               return ER_NONE; /* TODO: detail error code */
+       }
        return 0;
 }
 
@@ -485,63 +885,151 @@ EXPORT W http_connector_getevent(http_connector_t *connector, http_connector_eve
 
 EXPORT W http_connector_sendrequestline(http_connector_t *connector, ID endpoint, UB *path, W path_len)
 {
-       W err;
        http_reqentry_t *entry;
+       http_requestlinestream_t reqline;
+       W err, len;
+       Bool cont;
+       CONST UB *str;
+
+       HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
 
        HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_REQUEST_LINE, entry);
 
+       err = http_requestlinestream_initialize(&reqline, entry->method, path, path_len);
+       if (err < 0) {
+               HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
+               return err;
+       }
+       for (;;) {
+               cont = http_requestlinestream_make(&reqline, &str, &len);
+               if (cont == False) {
+                       break;
+               }
+               err = http_transport_write(connector->transport, entry->transport, str, len);
+               if (err < 0) {
+                       break;
+               }
+       }
+       http_requestlinestream_finalize(&reqline);
+
+       if (err < 0) {
+               HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
+               return err;
+       }
+
        entry->snd_state = SEND_HEADER_MINE;
 
+       HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
+
        return 0;
 }
 
+LOCAL W http_connector_writedefaultheader(http_connector_t *connector, ID transport, UB *host, W host_len)
+{
+       http_defaultheaderstream_t defaultheader;
+       W err = 0, len;
+       Bool cont;
+       CONST UB *str;
+
+       http_defaultheaderstream_initialize(&defaultheader, host, host_len);
+       for (;;) {
+               cont = http_defaultheaderstream_make(&defaultheader, &str, &len);
+               if (cont == False) {
+                       break;
+               }
+               err = http_transport_write(connector->transport, transport, str, len);
+               if (err < 0) {
+                       break;
+               }
+       }
+       http_defaultheaderstream_finalize(&defaultheader);
+
+       return err;
+}
+
 EXPORT W http_connector_sendheader(http_connector_t *connector, ID endpoint, UB *p, W len)
 {
-       W err;
        http_reqentry_t *entry;
+       W err;
+
+       HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
 
        HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, SEND_HEADER_MINE, SEND_HEADER_USER, entry);
 
        if (entry->snd_state == SEND_HEADER_MINE) {
+               err = http_connector_writedefaultheader(connector, entry->transport, entry->host, entry->host_len);
+               if (err < 0) {
+                       HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
+                       return err;
+               }
                entry->snd_state = SEND_HEADER_USER;
        }
 
+       HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
+
        return 0;
 }
 
 EXPORT W http_connector_sendheaderend(http_connector_t *connector, ID endpoint)
 {
-       W err;
        http_reqentry_t *entry;
+       W err;
+
+       HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
 
        HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, SEND_HEADER_MINE, SEND_HEADER_USER, entry);
 
        if (entry->snd_state == SEND_HEADER_MINE) {
+               err = http_connector_writedefaultheader(connector, entry->transport, entry->host, entry->host_len);
+               if (err < 0) {
+                       HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
+                       return err;
+               }
+       }
+       err = http_transport_write(connector->transport, entry->transport, "\r\n", 2);
+       if (err < 0) {
+               HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
+               return err;
        }
 
        entry->snd_state = SEND_MESSAGE_BODY;
 
+       HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
+
        return 0;
 }
 
 EXPORT W http_connector_sendmessagebody(http_connector_t *connector, ID endpoint, UB *p, W len)
 {
-       W err;
        http_reqentry_t *entry;
+       W err;
+
+       HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
 
        HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_MESSAGE_BODY, entry);
 
+       err = http_transport_write(connector->transport, entry->transport, p, len);
+       HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
+       if (err < 0) {
+               return err;
+       }
+
        return 0;
 }
 
 EXPORT W http_connector_sendmessagebodyend(http_connector_t *connector, ID endpoint)
 {
        http_reqentry_t *entry;
+       W err;
+
+       HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
 
        HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_MESSAGE_BODY, entry);
 
        entry->status = WAITING_RESPONSE;
 
+       HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
+
        return 0;
 }
 
@@ -564,9 +1052,23 @@ EXPORT http_connector_t* http_connector_new()
                DP_ER("cre_flg", connector->flg);
                goto error_flg;
        }
+       connector->sem = cre_sem(1, SEM_EXCL|DELEXIT);
+       if (connector->sem < 0) {
+               DP_ER("cre_sem", connector->sem);
+               goto error_sem;
+       }
+       connector->transport = http_transport_new(10/*tmp*/);
+       if (connector->transport == NULL) {
+               DP_ER("http_transport_new", -1);
+               goto error_transport;
+       }
 
        return connector;
 
+       http_transport_delete(connector->transport);
+error_transport:
+       del_sem(connector->sem);
+error_sem:
        del_flg(connector->flg);
 error_flg:
        http_reqdict_delete(connector->dict);
@@ -577,6 +1079,8 @@ error_http_reqdict:
 
 EXPORT VOID http_connector_delete(http_connector_t *connector)
 {
+       http_transport_delete(connector->transport);
+       del_sem(connector->sem);
        del_flg(connector->flg);
        http_reqdict_delete(connector->dict);
        free(connector);