#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,
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];
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;
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;
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 */
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 (;;) {
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 (;;) {
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);
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 (;;) {
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);
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;
}
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 (;;) {
}
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);
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;
}
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) {
}
return ER_NONE; /* TODO: detail error code */
}
+ if (event->type == HTTP_CONNECTOR_EVENTTYPE_NONE) {
+ return ER_NONE; /* TODO: detail error code */
+ }
return 0;
}
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;
}
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);
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);