4 * Copyright (c) 2012-2014 project bchan
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.
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:
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.
19 * 2. Altered source versions must be plainly marked as such, and must not be
20 * misrepresented as being the original software.
22 * 3. This notice may not be removed or altered from any source
27 #include "http_connector.h"
33 #include <btron/btron.h>
34 #include <btron/bsocket.h>
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"
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)
50 # define DP_ER(msg, err) /**/
54 # define DP_STATE(state) printf("%s\n", state)
56 # define DP_STATE(state) /**/
59 struct http_reqentry_t_ {
82 RECEIVE_MESSAGE_BODY_TRANSFERDECODE,
83 RECEIVE_MESSAGE_BODY_CONTENTDECODE,
94 http_statuslineparser_t sl;
95 http_defaultheaderparser_t dh;
96 http_transferdecoder_t tc;
97 http_contentdecoder_t cc;
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;
108 typedef struct http_reqentry_t_ http_reqentry_t;
110 LOCAL VOID http_reqentry_attachendpoint(http_reqentry_t *entry, http_transport_t *transport, ID endpoint)
112 http_transport_holdendpoint(transport, endpoint);
113 entry->status = SENDING_REQUEST;
114 entry->transport = endpoint;
118 LOCAL VOID http_reqentry_detachendpoint(http_reqentry_t *entry, http_transport_t *transport, Bool transport_close)
120 http_transport_releaseendpoint(transport, entry->transport, transport_close);
121 entry->transport = -1;
125 LOCAL W http_reqentry_initialize(http_reqentry_t *entry, UB *host, W host_len, UH port, HTTP_METHOD method)
130 struct sockaddr_in *addr_in;
132 entry->host = malloc(sizeof(UB)*(host_len+1));
133 if (entry->host == NULL) {
134 err = ER_NOMEM; /* TODO: detail error code */
137 memcpy(entry->host, host, host_len);
138 entry->host[host_len] = '\0';
139 entry->host_len = host_len;
141 err = so_gethostbyname(entry->host, &ent, buf);
143 goto error_gethostbyname;
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]);
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;
157 http_statuslineparser_initialize(&entry->rcv_reader.sl);
158 http_defaultheaderparser_initialize(&entry->rcv_reader.dh);
165 entry->status = NON_EXISTENT;
169 LOCAL VOID http_reqentry_finalize(http_reqentry_t *entry)
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);
179 case RECEIVE_STATUS_LINE:
181 case RECEIVE_HEADER_END:
182 case RECEIVE_COMPLETED:
185 http_defaultheaderparser_finalize(&entry->rcv_reader.dh);
186 http_statuslineparser_finalize(&entry->rcv_reader.sl);
187 if (entry->host != NULL) {
192 struct http_reqdict_t_ {
195 http_reqentry_t entry[1];
197 typedef struct http_reqdict_t_ http_reqdict_t;
200 idtocb_iterator_t base;
201 } http_recdictiterator_t;
203 LOCAL Bool http_reqdictiterator_next(http_recdictiterator_t *iter, http_reqentry_t **entry)
205 return idtocb_iterator_next(&iter->base, (idtocb_entry_t**)entry);
208 LOCAL VOID http_reqdictiterator_initialize(http_recdictiterator_t *iter, http_reqdict_t *dict)
210 idtocb_iterator_initialize(&iter->base, dict->base);
213 LOCAL VOID http_reqdictiterator_finalize(http_recdictiterator_t *iter)
215 idtocb_iterator_finalize(&iter->base);
218 LOCAL ID http_reqdict_allocate(http_reqdict_t *dict, UB *host, W host_len, UH port, HTTP_METHOD method)
224 id = idtocb_allocate(dict->base);
228 err = idtocb_getcontrolblock(dict->base, id, (idtocb_entry_t**)&cb);
230 idtocb_free(dict->base, id);
234 err = http_reqentry_initialize(cb, host, host_len, port, method);
236 idtocb_free(dict->base, id);
243 LOCAL http_reqentry_t* http_reqdict_getentrybyID(http_reqdict_t *dict, ID id)
245 http_reqentry_t *entry;
248 err = idtocb_getcontrolblock(dict->base, id, (idtocb_entry_t**)&entry);
255 LOCAL VOID http_reqdict_free(http_reqdict_t *dict, ID id)
257 http_reqentry_t *entry;
260 err = idtocb_getcontrolblock(dict->base, id, (idtocb_entry_t**)&entry);
264 http_reqentry_finalize(entry);
265 idtocb_free(dict->base, id);
268 LOCAL http_reqdict_t* http_reqdict_new(W max_entries)
270 http_reqdict_t *dict;
272 dict = (http_reqdict_t*)malloc(sizeof(http_reqdict_t));
276 dict->base = idtocb_new(sizeof(http_reqentry_t), max_entries);
277 if (dict->base == NULL) {
284 LOCAL VOID http_reqdict_delete(http_reqdict_t *dict)
286 http_recdictiterator_t iter;
287 http_reqentry_t *entry;
290 http_reqdictiterator_initialize(&iter, dict);
292 cont = http_reqdictiterator_next(&iter, &entry);
296 http_reqentry_finalize(entry);
298 http_reqdictiterator_finalize(&iter);
300 idtocb_delete(dict->base);
304 struct http_connector_t_ {
305 http_reqdict_t *dict;
306 http_transport_t *transport;
311 #define HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector) \
312 err = wai_sem((connector)->sem, T_FOREVER); \
316 #define HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_VOID(connector) \
317 err = wai_sem((connector)->sem, T_FOREVER); \
321 #define HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector) \
322 sig_sem((connector)->sem);
324 #define HTTP_CONNECTOR_FLAG_CREARMASK(flag) (~(flag))
325 #define HTTP_CONNECTOR_FLAG_REQUEST 0x00000001
326 #define HTTP_CONNECTOR_FLAG_EVENT 0x00000002
327 #define HTTP_CONNECTOR_FLAG_CLEARMASK_REQUEST HTTP_CONNECTOR_FLAG_CREARMASK(HTTP_CONNECTOR_FLAG_REQUEST)
328 #define HTTP_CONNECTOR_FLAG_CLEARMASK_EVENT HTTP_CONNECTOR_FLAG_CREARMASK(HTTP_CONNECTOR_FLAG_EVENT)
330 EXPORT ID http_connector_createendpoint(http_connector_t *connector, UB *host, W host_len, UH port, HTTP_METHOD method)
335 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
336 id = http_reqdict_allocate(connector->dict, host, host_len, port, method);
337 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
339 DP_ER("http_reqdict_allocate", id);
340 return id; /* TODO */
343 err = set_flg(connector->flg, HTTP_CONNECTOR_FLAG_REQUEST);
345 DP_ER("set_flg", err);
346 http_reqdict_free(connector->dict, id);
353 EXPORT VOID http_connector_deleteendpoint(http_connector_t *connector, ID endpoint)
355 http_reqentry_t *entry;
356 Bool transport_close = True;
359 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_VOID(connector);
361 entry = http_reqdict_getentrybyID(connector->dict, endpoint);
363 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
367 switch (entry->status) {
368 case SENDING_REQUEST:
369 if (entry->snd_state == SEND_REQUEST_LINE) {
370 transport_close = False;
374 case WAITING_RESPONSE:
375 case RECEIVING_RESPONSE:
376 http_reqentry_detachendpoint(entry, connector->transport, transport_close);
379 case WAITING_TRANSPORT:
380 case ABORTED_BY_TRANSPORT:
384 http_reqdict_free(connector->dict, endpoint);
386 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
389 LOCAL W http_connector_searchwaiting(http_connector_t *connector)
392 http_reqentry_t *entry;
393 http_recdictiterator_t iter;
397 http_reqdictiterator_initialize(&iter, connector->dict);
399 cont = http_reqdictiterator_next(&iter, &entry);
403 if (entry->status == WAITING_TRANSPORT) {
404 endpoint = http_transport_searchendpoint(connector->transport, &entry->addr);
405 if ((endpoint & 0xFFFF0000) == ER_NOEXS) {
406 endpoint = http_transport_prepairendpoint(connector->transport, &entry->addr);
410 } else if (endpoint < 0) {
413 http_transport_isholdedendpoint(connector->transport, endpoint, &holded);
414 if (holded != False) {
417 http_reqentry_attachendpoint(entry, connector->transport, endpoint);
421 http_reqdictiterator_finalize(&iter);
426 LOCAL Bool http_connector_isexistwaiting(http_connector_t *connector)
428 http_reqentry_t *entry;
429 http_recdictiterator_t iter;
430 Bool cont, ret = False;
432 http_reqdictiterator_initialize(&iter, connector->dict);
434 cont = http_reqdictiterator_next(&iter, &entry);
438 if (entry->status == WAITING_TRANSPORT) {
441 } else if (entry->status == SENDING_REQUEST) {
444 } else if (entry->status == WAITING_RESPONSE) {
447 } else if (entry->status == RECEIVING_RESPONSE) {
452 http_reqdictiterator_finalize(&iter);
457 LOCAL W http_connector_waitreceiving(http_connector_t *connector, TMOUT tmout)
460 http_reqentry_t *entry;
461 http_recdictiterator_t iter;
464 http_reqdictiterator_initialize(&iter, connector->dict);
466 cont = http_reqdictiterator_next(&iter, &entry);
470 if (entry->status == WAITING_RESPONSE) {
471 http_transport_setwaitingreceive(connector->transport, entry->transport);
474 http_reqdictiterator_finalize(&iter);
476 http_transport_waitreceive(connector->transport, tmout);
478 http_reqdictiterator_initialize(&iter, connector->dict);
480 cont = http_reqdictiterator_next(&iter, &entry);
484 if (entry->status == WAITING_RESPONSE) {
485 http_transport_isreadready(connector->transport, entry->transport, &is_ready);
486 if (is_ready != False) {
487 entry->status = RECEIVING_RESPONSE;
492 http_reqdictiterator_finalize(&iter);
497 EXPORT W http_connector_waitconnection(http_connector_t *connector, TMOUT tmout)
500 Bool evt = False, exist;
502 err = wai_flg(connector->flg, HTTP_CONNECTOR_FLAG_REQUEST, WF_AND|NOCLR, tmout);
507 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
508 err = http_connector_searchwaiting(connector);
510 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
516 http_transport_releaseunusedendpoint(connector->transport);
518 exist = http_connector_isexistwaiting(connector);
519 if (exist == False) {
520 clr_flg(connector->flg, HTTP_CONNECTOR_FLAG_CLEARMASK_REQUEST);
523 err = http_connector_waitreceiving(connector, tmout);
524 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
533 err = set_flg(connector->flg, HTTP_CONNECTOR_FLAG_EVENT);
535 DP_ER("set_flg", err);
542 LOCAL W http_connector_rcv_status_line(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
544 http_statuslineparser_result result;
549 err = http_transport_read(connector->transport, entry->transport, &bin, &len);
551 DP_ER("http_transport_read", err);
555 for (i = 0; i < len; i++) {
556 end = http_statuslineparser_inputchar(&entry->rcv_reader.sl, bin[i], &result);
563 http_transport_consumereadbuffer(connector->transport, entry->transport, i);
566 if (result.error != HTTP_STATUSLINEPARSER_ERROR_NONE) {
567 return -1; /* TODO */
569 entry->rcv_state = RECEIVE_HEADER;
570 event->endpoint = entry->base.id;
571 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_STATUSLINE;
572 event->data.receive_statusline.version = result.version;
573 event->data.receive_statusline.statuscode = result.statuscode;
580 LOCAL W http_connector_rcv_header(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
582 HTTP_DEFAULTHEADERPARSER_RESULT result;
587 err = http_transport_read(connector->transport, entry->transport, &bin, &len);
589 DP_ER("http_transport_read", err);
593 for (i = 0; i < len; i++) {
594 http_defaultheaderparser_inputchar(&entry->rcv_reader.dh, bin[i], &result);
595 if (result == HTTP_DEFAULTHEADERPARSER_RESULT_MESSAGE_HEADER_END) {
602 http_transport_consumereadbuffer(connector->transport, entry->transport, i);
605 entry->rcv_state = RECEIVE_HEADER_END;
608 event->endpoint = entry->base.id;
609 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_HEADER;
610 event->data.receive_header.bin = bin;
611 event->data.receive_header.len = i;
616 LOCAL W http_connector_rcv_header_end(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
620 HTTP_TRANSFERCODING_TYPE transfer_coding;
621 HTTP_CONTENTCODING_VALUE content_coding;
623 entry->rcv_state = RECEIVE_MESSAGE_BODY;
624 event->endpoint = entry->base.id;
625 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_HEADER_END;
627 content_length = http_defaultheaderparsr_contentlength(&entry->rcv_reader.dh);
628 transfer_coding = http_defaultheaderparsr_transferencoding(&entry->rcv_reader.dh);
629 content_coding = http_defaultheaderparsr_contentencoding(&entry->rcv_reader.dh);
631 http_transferdecoder_initialize(&entry->rcv_reader.tc, transfer_coding, content_length);
632 err = http_contentdecoder_initialize(&entry->rcv_reader.cc, content_coding);
636 entry->rcv_reader.body.transfer_result = NULL;
637 entry->rcv_reader.body.transfer_result_len = 0;
638 entry->rcv_reader.body.transfer_result_consumed = 0;
639 entry->rcv_reader.body.content_result = NULL;
640 entry->rcv_reader.body.content_result_len = 0;
641 entry->rcv_reader.body.content_result_consumed = 0;
646 LOCAL W http_connector_rcv_message_body_contentdecode(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
649 http_contentdecoder_result *result;
651 if (entry->rcv_reader.body.content_result_consumed == entry->rcv_reader.body.content_result_len) {
652 err = http_contentdecoder_outputdata(&entry->rcv_reader.cc, &entry->rcv_reader.body.content_result, &entry->rcv_reader.body.content_result_len);
654 DP_ER("http_contentdecoder_outputdata", err);
657 entry->rcv_reader.body.content_result_consumed = 0;
658 if (entry->rcv_reader.body.content_result_len == 0) {
662 result = entry->rcv_reader.body.content_result + entry->rcv_reader.body.content_result_consumed;
663 entry->rcv_reader.body.content_result_consumed++;
664 switch (result->type) {
665 case HTTP_CONTENTDECODER_RESULTTYPE_DATA:
666 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_MESSAGEBODY;
667 event->endpoint = entry->base.id;
668 event->data.receive_messagebody.bin = result->data;
669 event->data.receive_messagebody.len = result->len;
671 case HTTP_CONTENTDECODER_RESULTTYPE_NEED_INPUT:
672 entry->rcv_state = RECEIVE_MESSAGE_BODY_TRANSFERDECODE;
674 case HTTP_CONTENTDECODER_RESULTTYPE_END:
675 entry->rcv_state = RECEIVE_MESSAGE_END;
682 LOCAL W http_connector_rcv_message_body_transferdecode(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
684 http_transferdecoder_result *result;
687 if (entry->rcv_reader.body.transfer_result_consumed == entry->rcv_reader.body.transfer_result_len) {
688 entry->rcv_state = RECEIVE_MESSAGE_BODY;
692 result = entry->rcv_reader.body.transfer_result + entry->rcv_reader.body.transfer_result_consumed;
693 switch (result->type) {
694 case HTTP_TRANSFERDECODER_RESULTTYPE_DATA:
695 err = http_contentdecoder_inputentitybody(&entry->rcv_reader.cc, result->data, result->len);
697 case HTTP_TRANSFERDECODER_RESULTTYPE_END:
698 err = http_contentdecoder_inputendofdata(&entry->rcv_reader.cc);
703 entry->rcv_reader.body.transfer_result_consumed++;
705 DP_ER("http_contentdecoder_inputXXX", err);
708 entry->rcv_state = RECEIVE_MESSAGE_BODY_CONTENTDECODE;
710 return http_connector_rcv_message_body_contentdecode(connector, entry, event);
713 LOCAL W http_connector_rcv_message_body(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
718 err = http_transport_read(connector->transport, entry->transport, &bin, &len);
720 DP_ER("http_transport_read", err);
724 len = http_transferdecoder_inputentitybody(&entry->rcv_reader.tc, bin, len, &entry->rcv_reader.body.transfer_result, &entry->rcv_reader.body.transfer_result_len);
725 entry->rcv_reader.body.transfer_result_consumed = 0;
726 http_transport_consumereadbuffer(connector->transport, entry->transport, len);
728 entry->rcv_state = RECEIVE_MESSAGE_BODY_TRANSFERDECODE;
730 return http_connector_rcv_message_body_transferdecode(connector, entry, event);
733 LOCAL W http_connector_rcv_message_end(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
735 Bool connection_closed;
737 http_contentdecoder_finalize(&entry->rcv_reader.cc);
738 http_transferdecoder_finalize(&entry->rcv_reader.tc);
739 connection_closed = http_defaultheaderparser_connectionclosed(&entry->rcv_reader.dh);
741 entry->status = COMPLETED;
742 entry->rcv_state = RECEIVE_COMPLETED;
743 event->endpoint = entry->base.id;
744 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_MESSAGEBODY_END;
746 http_reqentry_detachendpoint(entry, connector->transport, connection_closed);
751 LOCAL W http_connector_handleevent_receiving_response(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
755 switch (entry->rcv_state) {
756 case RECEIVE_STATUS_LINE:
757 DP_STATE("RECEIVE_STATUS_LINE");
758 err = http_connector_rcv_status_line(connector, entry, event);
761 DP_STATE("RECEIVE_RECEIVE_HEADER");
762 err = http_connector_rcv_header(connector, entry, event);
764 case RECEIVE_HEADER_END:
765 DP_STATE("RECEIVE_HEADER_END");
766 err = http_connector_rcv_header_end(connector, entry, event);
768 case RECEIVE_MESSAGE_BODY:
769 DP_STATE("RECEIVE_MESSAGE_BODY");
770 err = http_connector_rcv_message_body(connector, entry, event);
772 case RECEIVE_MESSAGE_BODY_TRANSFERDECODE:
773 DP_STATE("RECEIVE_MESSAGE_BODY_TRANSFERDECODE");
774 err = http_connector_rcv_message_body_transferdecode(connector, entry, event);
776 case RECEIVE_MESSAGE_BODY_CONTENTDECODE:
777 DP_STATE("RECEIVE_MESSAGE_BODY_CONTENTDECDE");
778 err = http_connector_rcv_message_body_contentdecode(connector, entry, event);
780 case RECEIVE_MESSAGE_END:
781 DP_STATE("RECEIVE_MESSAGE_END");
782 err = http_connector_rcv_message_end(connector, entry, event);
784 case RECEIVE_COMPLETED:
785 DP_STATE("RECEIVE_COMPLETED");
793 /* TODO: devide event found and need loop for state transition */
794 EXPORT Bool http_connector_searcheventtarget(http_connector_t *connector, http_connector_event *event)
796 http_reqentry_t *entry;
797 http_recdictiterator_t iter;
798 Bool cont, found = False;
801 event->type = HTTP_CONNECTOR_EVENTTYPE_NONE;
803 http_reqdictiterator_initialize(&iter, connector->dict);
805 cont = http_reqdictiterator_next(&iter, &entry);
809 if (entry->status == SENDING_REQUEST) {
810 event->type = HTTP_CONNECTOR_EVENTTYPE_SEND;
811 event->endpoint = entry->base.id;
815 if (entry->status == RECEIVING_RESPONSE) {
816 err = http_connector_handleevent_receiving_response(connector, entry, event);
817 if ((err < 0)&&((err & 0xFFFF0000) != EX_WOULDBLOCK)) {
818 event->type = HTTP_CONNECTOR_EVENTTYPE_ERROR;
819 event->endpoint = entry->base.id;
820 entry->status = ABORTED_BY_TRANSPORT;
821 http_reqentry_detachendpoint(entry, connector->transport, True);
830 http_reqdictiterator_finalize(&iter);
835 EXPORT W http_connector_getevent(http_connector_t *connector, http_connector_event *event)
840 err = wai_flg(connector->flg, HTTP_CONNECTOR_FLAG_EVENT, WF_AND|NOCLR, T_NOWAIT);
841 if ((err & 0xFFFF0000) == ER_NONE) {
845 DP_ER("wai_flg", err);
848 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
849 found = http_connector_searcheventtarget(connector, event);
850 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
851 if (found == False) {
852 err = clr_flg(connector->flg, HTTP_CONNECTOR_FLAG_CLEARMASK_EVENT);
854 DP_ER("clr_flg", err);
857 return ER_NONE; /* TODO: detail error code */
859 if (event->type == HTTP_CONNECTOR_EVENTTYPE_NONE) {
860 return ER_NONE; /* TODO: detail error code */
865 #define HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, state, entry) \
866 (entry) = http_reqdict_getentrybyID((connector)->dict, (endpoint)); \
867 if ((entry) == NULL) { \
868 return ER_NOEXS; /* TODO: detail error code */ \
870 if ((entry)->status != SENDING_REQUEST) { \
871 return ER_PAR; /* TODO: suitable error code */ \
873 if ((entry)->snd_state != (state)) { \
874 return ER_PAR; /* TODO: suitable error code */ \
877 #define HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, state1, state2, entry) \
878 (entry) = http_reqdict_getentrybyID((connector)->dict, (endpoint)); \
879 if ((entry) == NULL) { \
880 return ER_NOEXS; /* TODO: detail error code */ \
882 if ((entry)->status != SENDING_REQUEST) { \
883 return ER_PAR; /* TODO: suitable error code */ \
885 if (((entry)->snd_state != (state1))&&((entry)->snd_state != (state2))) { \
886 return ER_PAR; /* TODO: suitable error code */ \
889 EXPORT W http_connector_sendrequestline(http_connector_t *connector, ID endpoint, UB *path, W path_len)
891 http_reqentry_t *entry;
892 http_requestlinestream_t reqline;
897 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
899 HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_REQUEST_LINE, entry);
901 err = http_requestlinestream_initialize(&reqline, entry->method, path, path_len);
903 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
907 cont = http_requestlinestream_make(&reqline, &str, &len);
911 err = http_transport_write(connector->transport, entry->transport, str, len);
916 http_requestlinestream_finalize(&reqline);
919 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
923 entry->snd_state = SEND_HEADER_MINE;
925 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
930 LOCAL W http_connector_writedefaultheader(http_connector_t *connector, ID transport, UB *host, W host_len)
932 http_defaultheaderstream_t defaultheader;
937 http_defaultheaderstream_initialize(&defaultheader, host, host_len);
939 cont = http_defaultheaderstream_make(&defaultheader, &str, &len);
943 err = http_transport_write(connector->transport, transport, str, len);
948 http_defaultheaderstream_finalize(&defaultheader);
953 EXPORT W http_connector_sendheader(http_connector_t *connector, ID endpoint, UB *p, W len)
955 http_reqentry_t *entry;
958 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
960 HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, SEND_HEADER_MINE, SEND_HEADER_USER, entry);
962 if (entry->snd_state == SEND_HEADER_MINE) {
963 err = http_connector_writedefaultheader(connector, entry->transport, entry->host, entry->host_len);
965 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
968 entry->snd_state = SEND_HEADER_USER;
971 err = http_transport_write(connector->transport, entry->transport, p, len);
973 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
978 EXPORT W http_connector_sendheaderend(http_connector_t *connector, ID endpoint)
980 http_reqentry_t *entry;
983 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
985 HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, SEND_HEADER_MINE, SEND_HEADER_USER, entry);
987 if (entry->snd_state == SEND_HEADER_MINE) {
988 err = http_connector_writedefaultheader(connector, entry->transport, entry->host, entry->host_len);
990 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
994 err = http_transport_write(connector->transport, entry->transport, "\r\n", 2);
996 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1000 entry->snd_state = SEND_MESSAGE_BODY;
1002 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1007 EXPORT W http_connector_sendmessagebody(http_connector_t *connector, ID endpoint, UB *p, W len)
1009 http_reqentry_t *entry;
1012 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
1014 HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_MESSAGE_BODY, entry);
1016 err = http_transport_write(connector->transport, entry->transport, p, len);
1017 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1025 EXPORT W http_connector_sendmessagebodyend(http_connector_t *connector, ID endpoint)
1027 http_reqentry_t *entry;
1030 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
1032 HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_MESSAGE_BODY, entry);
1034 entry->status = WAITING_RESPONSE;
1036 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1041 EXPORT http_connector_t* http_connector_new()
1043 http_connector_t *connector;
1045 connector = (http_connector_t*)malloc(sizeof(http_connector_t));
1046 if (connector == NULL) {
1050 connector->dict = http_reqdict_new(10/*tmp*/);
1051 if (connector->dict == NULL) {
1052 DP_ER("http_recdict_new", 0);
1053 goto error_http_reqdict;
1055 connector->flg = cre_flg(0, DELEXIT);
1056 if (connector->flg < 0) {
1057 DP_ER("cre_flg", connector->flg);
1060 connector->sem = cre_sem(1, SEM_EXCL|DELEXIT);
1061 if (connector->sem < 0) {
1062 DP_ER("cre_sem", connector->sem);
1065 connector->transport = http_transport_new(10/*tmp*/);
1066 if (connector->transport == NULL) {
1067 DP_ER("http_transport_new", -1);
1068 goto error_transport;
1073 http_transport_delete(connector->transport);
1075 del_sem(connector->sem);
1077 del_flg(connector->flg);
1079 http_reqdict_delete(connector->dict);
1085 EXPORT VOID http_connector_delete(http_connector_t *connector)
1087 http_transport_delete(connector->transport);
1088 del_sem(connector->sem);
1089 del_flg(connector->flg);
1090 http_reqdict_delete(connector->dict);