4 * Copyright (c) 2012-2015 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_ {
84 RECEIVE_MESSAGE_BODY_TRANSFERDECODE,
85 RECEIVE_MESSAGE_BODY_CONTENTDECODE,
96 http_statuslineparser_t sl;
97 http_defaultheaderparser_t dh;
98 http_transferdecoder_t tc;
99 http_contentdecoder_t cc;
101 http_transferdecoder_result *transfer_result;
102 W transfer_result_len;
103 W transfer_result_consumed;
104 http_contentdecoder_result *content_result;
105 W content_result_len;
106 W content_result_consumed;
110 typedef struct http_reqentry_t_ http_reqentry_t;
112 LOCAL VOID http_reqentry_attachendpoint(http_reqentry_t *entry, http_transport_t *transport, ID endpoint)
114 http_transport_holdendpoint(transport, endpoint);
115 entry->status = SENDING_REQUEST;
116 entry->transport = endpoint;
120 LOCAL VOID http_reqentry_detachendpoint(http_reqentry_t *entry, http_transport_t *transport, Bool transport_close)
122 http_transport_releaseendpoint(transport, entry->transport, transport_close);
123 entry->transport = -1;
127 LOCAL W http_reqentry_initialize(http_reqentry_t *entry, UB *host, W host_len, UH port, HTTP_METHOD method)
133 struct sockaddr_in *addr_in;
135 entry->host = malloc(sizeof(UB)*(host_len+1));
136 if (entry->host == NULL) {
137 err = ER_NOMEM; /* TODO: detail error code */
140 memcpy(entry->host, host, host_len);
141 entry->host[host_len] = '\0';
142 entry->host_len = host_len;
144 err = inet_aton(host, &addr);
146 err = so_gethostbyname(entry->host, &ent, buf);
148 goto error_gethostbyname;
150 addr.s_addr = *(unsigned int *)(ent.h_addr_list[0]);
152 addr_in = (struct sockaddr_in *)&(entry->addr);
153 addr_in->sin_family = AF_INET;
154 addr_in->sin_port = htons( port );
155 addr_in->sin_addr = addr;
157 entry->aborted_by_user = False;
158 entry->status = WAITING_TRANSPORT;
159 entry->snd_state = SEND_REQUEST_LINE;
160 entry->rcv_state = RECEIVE_STATUS_LINE;
161 entry->method = method;
162 entry->transport = -1;
164 http_statuslineparser_initialize(&entry->rcv_reader.sl);
165 http_defaultheaderparser_initialize(&entry->rcv_reader.dh);
172 entry->status = NON_EXISTENT;
176 LOCAL VOID http_reqentry_finalize(http_reqentry_t *entry)
178 switch (entry->rcv_state) {
179 case RECEIVE_MESSAGE_BODY:
180 case RECEIVE_MESSAGE_BODY_TRANSFERDECODE:
181 case RECEIVE_MESSAGE_BODY_CONTENTDECODE:
182 case RECEIVE_MESSAGE_END:
183 http_contentdecoder_finalize(&entry->rcv_reader.cc);
184 http_transferdecoder_finalize(&entry->rcv_reader.tc);
186 case RECEIVE_STATUS_LINE:
188 case RECEIVE_HEADER_END:
189 case RECEIVE_COMPLETED:
192 http_defaultheaderparser_finalize(&entry->rcv_reader.dh);
193 http_statuslineparser_finalize(&entry->rcv_reader.sl);
194 if (entry->host != NULL) {
199 struct http_reqdict_t_ {
202 http_reqentry_t entry[1];
204 typedef struct http_reqdict_t_ http_reqdict_t;
207 idtocb_iterator_t base;
208 } http_recdictiterator_t;
210 LOCAL Bool http_reqdictiterator_next(http_recdictiterator_t *iter, http_reqentry_t **entry)
212 return idtocb_iterator_next(&iter->base, (idtocb_entry_t**)entry);
215 LOCAL VOID http_reqdictiterator_initialize(http_recdictiterator_t *iter, http_reqdict_t *dict)
217 idtocb_iterator_initialize(&iter->base, dict->base);
220 LOCAL VOID http_reqdictiterator_finalize(http_recdictiterator_t *iter)
222 idtocb_iterator_finalize(&iter->base);
225 LOCAL ID http_reqdict_allocate(http_reqdict_t *dict, UB *host, W host_len, UH port, HTTP_METHOD method)
231 id = idtocb_allocate(dict->base);
235 err = idtocb_getcontrolblock(dict->base, id, (idtocb_entry_t**)&cb);
237 idtocb_free(dict->base, id);
241 err = http_reqentry_initialize(cb, host, host_len, port, method);
243 idtocb_free(dict->base, id);
250 LOCAL http_reqentry_t* http_reqdict_getentrybyID(http_reqdict_t *dict, ID id)
252 http_reqentry_t *entry;
255 err = idtocb_getcontrolblock(dict->base, id, (idtocb_entry_t**)&entry);
262 LOCAL VOID http_reqdict_free(http_reqdict_t *dict, ID id)
264 http_reqentry_t *entry;
267 err = idtocb_getcontrolblock(dict->base, id, (idtocb_entry_t**)&entry);
271 http_reqentry_finalize(entry);
272 idtocb_free(dict->base, id);
275 LOCAL http_reqdict_t* http_reqdict_new(W max_entries)
277 http_reqdict_t *dict;
279 dict = (http_reqdict_t*)malloc(sizeof(http_reqdict_t));
283 dict->base = idtocb_new(sizeof(http_reqentry_t), max_entries);
284 if (dict->base == NULL) {
291 LOCAL VOID http_reqdict_delete(http_reqdict_t *dict)
293 http_recdictiterator_t iter;
294 http_reqentry_t *entry;
297 http_reqdictiterator_initialize(&iter, dict);
299 cont = http_reqdictiterator_next(&iter, &entry);
303 http_reqentry_finalize(entry);
305 http_reqdictiterator_finalize(&iter);
307 idtocb_delete(dict->base);
311 struct http_connector_t_ {
312 http_reqdict_t *dict;
313 http_transport_t *transport;
318 #define HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector) \
319 err = wai_sem((connector)->sem, T_FOREVER); \
323 #define HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_VOID(connector) \
324 err = wai_sem((connector)->sem, T_FOREVER); \
328 #define HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector) \
329 sig_sem((connector)->sem);
331 #define HTTP_CONNECTOR_FLAG_CREARMASK(flag) (~(flag))
332 #define HTTP_CONNECTOR_FLAG_REQUEST 0x00000001
333 #define HTTP_CONNECTOR_FLAG_EVENT 0x00000002
334 #define HTTP_CONNECTOR_FLAG_CLEARMASK_REQUEST HTTP_CONNECTOR_FLAG_CREARMASK(HTTP_CONNECTOR_FLAG_REQUEST)
335 #define HTTP_CONNECTOR_FLAG_CLEARMASK_EVENT HTTP_CONNECTOR_FLAG_CREARMASK(HTTP_CONNECTOR_FLAG_EVENT)
337 EXPORT ID http_connector_createendpoint(http_connector_t *connector, UB *host, W host_len, UH port, HTTP_METHOD method)
342 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
343 id = http_reqdict_allocate(connector->dict, host, host_len, port, method);
344 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
346 DP_ER("http_reqdict_allocate", id);
347 return id; /* TODO */
350 err = set_flg(connector->flg, HTTP_CONNECTOR_FLAG_REQUEST);
352 DP_ER("set_flg", err);
353 http_reqdict_free(connector->dict, id);
360 EXPORT VOID http_connector_deleteendpoint(http_connector_t *connector, ID endpoint)
362 http_reqentry_t *entry;
363 Bool transport_close = True;
366 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_VOID(connector);
368 entry = http_reqdict_getentrybyID(connector->dict, endpoint);
370 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
374 switch (entry->status) {
375 case SENDING_REQUEST:
376 if (entry->snd_state == SEND_REQUEST_LINE) {
377 transport_close = False;
381 case WAITING_RESPONSE:
382 case RECEIVING_RESPONSE:
383 http_reqentry_detachendpoint(entry, connector->transport, transport_close);
386 case WAITING_TRANSPORT:
387 case DETECTING_ERROR:
388 case ABORTED_BY_TRANSPORT:
393 http_reqdict_free(connector->dict, endpoint);
395 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
398 LOCAL W http_connector_searchwaiting(http_connector_t *connector)
401 http_reqentry_t *entry;
402 http_recdictiterator_t iter;
406 http_reqdictiterator_initialize(&iter, connector->dict);
408 cont = http_reqdictiterator_next(&iter, &entry);
412 if (entry->status == WAITING_TRANSPORT) {
413 endpoint = http_transport_searchendpoint(connector->transport, &entry->addr);
414 if ((endpoint & 0xFFFF0000) == ER_NOEXS) {
415 endpoint = http_transport_prepairendpoint(connector->transport, &entry->addr);
417 entry->status = DETECTING_ERROR;
421 } else if (endpoint < 0) {
424 http_transport_isholdedendpoint(connector->transport, endpoint, &holded);
425 if (holded != False) {
428 http_reqentry_attachendpoint(entry, connector->transport, endpoint);
432 http_reqdictiterator_finalize(&iter);
437 LOCAL Bool http_connector_isexistwaiting(http_connector_t *connector)
439 http_reqentry_t *entry;
440 http_recdictiterator_t iter;
441 Bool cont, ret = False;
443 http_reqdictiterator_initialize(&iter, connector->dict);
445 cont = http_reqdictiterator_next(&iter, &entry);
449 if (entry->status == WAITING_TRANSPORT) {
452 } else if (entry->status == DETECTING_ERROR) {
455 } else if (entry->status == SENDING_REQUEST) {
458 } else if (entry->status == WAITING_RESPONSE) {
461 } else if (entry->status == RECEIVING_RESPONSE) {
466 http_reqdictiterator_finalize(&iter);
471 LOCAL W http_connector_waitreceiving(http_connector_t *connector, TMOUT tmout)
474 http_reqentry_t *entry;
475 http_recdictiterator_t iter;
478 http_reqdictiterator_initialize(&iter, connector->dict);
480 cont = http_reqdictiterator_next(&iter, &entry);
484 if (entry->status == WAITING_RESPONSE) {
485 http_transport_setwaitingreceive(connector->transport, entry->transport);
488 http_reqdictiterator_finalize(&iter);
490 http_transport_waitreceive(connector->transport, tmout);
492 http_reqdictiterator_initialize(&iter, connector->dict);
494 cont = http_reqdictiterator_next(&iter, &entry);
498 if (entry->status == WAITING_RESPONSE) {
499 http_transport_isreadready(connector->transport, entry->transport, &is_ready);
500 if (is_ready != False) {
501 entry->status = RECEIVING_RESPONSE;
506 http_reqdictiterator_finalize(&iter);
511 EXPORT W http_connector_waitconnection(http_connector_t *connector, TMOUT tmout)
514 Bool evt = False, exist;
516 err = wai_flg(connector->flg, HTTP_CONNECTOR_FLAG_REQUEST, WF_AND|NOCLR, tmout);
521 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
522 err = http_connector_searchwaiting(connector);
524 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
530 http_transport_releaseunusedendpoint(connector->transport);
532 exist = http_connector_isexistwaiting(connector);
533 if (exist == False) {
534 clr_flg(connector->flg, HTTP_CONNECTOR_FLAG_CLEARMASK_REQUEST);
537 err = http_connector_waitreceiving(connector, tmout);
538 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
547 err = set_flg(connector->flg, HTTP_CONNECTOR_FLAG_EVENT);
549 DP_ER("set_flg", err);
556 LOCAL W http_connector_rcv_status_line(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
558 http_statuslineparser_result result;
563 err = http_transport_read(connector->transport, entry->transport, &bin, &len);
565 DP_ER("http_transport_read", err);
569 for (i = 0; i < len; i++) {
570 end = http_statuslineparser_inputchar(&entry->rcv_reader.sl, bin[i], &result);
577 http_transport_consumereadbuffer(connector->transport, entry->transport, i);
580 if (result.error != HTTP_STATUSLINEPARSER_ERROR_NONE) {
581 return -1; /* TODO */
583 entry->rcv_state = RECEIVE_HEADER;
584 event->endpoint = entry->base.id;
585 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_STATUSLINE;
586 event->data.receive_statusline.version = result.version;
587 event->data.receive_statusline.statuscode = result.statuscode;
594 LOCAL W http_connector_rcv_header(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
596 HTTP_DEFAULTHEADERPARSER_RESULT result;
601 err = http_transport_read(connector->transport, entry->transport, &bin, &len);
603 DP_ER("http_transport_read", err);
607 for (i = 0; i < len; i++) {
608 http_defaultheaderparser_inputchar(&entry->rcv_reader.dh, bin[i], &result);
609 if (result == HTTP_DEFAULTHEADERPARSER_RESULT_MESSAGE_HEADER_END) {
616 http_transport_consumereadbuffer(connector->transport, entry->transport, i);
619 entry->rcv_state = RECEIVE_HEADER_END;
622 event->endpoint = entry->base.id;
623 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_HEADER;
624 event->data.receive_header.bin = bin;
625 event->data.receive_header.len = i;
630 LOCAL W http_connector_rcv_header_end(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
634 HTTP_TRANSFERCODING_TYPE transfer_coding;
635 HTTP_CONTENTCODING_VALUE content_coding;
637 entry->rcv_state = RECEIVE_MESSAGE_BODY;
638 event->endpoint = entry->base.id;
639 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_HEADER_END;
641 content_length = http_defaultheaderparsr_contentlength(&entry->rcv_reader.dh);
642 transfer_coding = http_defaultheaderparsr_transferencoding(&entry->rcv_reader.dh);
643 content_coding = http_defaultheaderparsr_contentencoding(&entry->rcv_reader.dh);
645 http_transferdecoder_initialize(&entry->rcv_reader.tc, transfer_coding, content_length);
646 err = http_contentdecoder_initialize(&entry->rcv_reader.cc, content_coding);
650 entry->rcv_reader.body.transfer_result = NULL;
651 entry->rcv_reader.body.transfer_result_len = 0;
652 entry->rcv_reader.body.transfer_result_consumed = 0;
653 entry->rcv_reader.body.content_result = NULL;
654 entry->rcv_reader.body.content_result_len = 0;
655 entry->rcv_reader.body.content_result_consumed = 0;
660 LOCAL W http_connector_rcv_message_body_contentdecode(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
663 http_contentdecoder_result *result;
665 if (entry->rcv_reader.body.content_result_consumed == entry->rcv_reader.body.content_result_len) {
666 err = http_contentdecoder_outputdata(&entry->rcv_reader.cc, &entry->rcv_reader.body.content_result, &entry->rcv_reader.body.content_result_len);
668 DP_ER("http_contentdecoder_outputdata", err);
671 entry->rcv_reader.body.content_result_consumed = 0;
672 if (entry->rcv_reader.body.content_result_len == 0) {
676 result = entry->rcv_reader.body.content_result + entry->rcv_reader.body.content_result_consumed;
677 entry->rcv_reader.body.content_result_consumed++;
678 switch (result->type) {
679 case HTTP_CONTENTDECODER_RESULTTYPE_DATA:
680 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_MESSAGEBODY;
681 event->endpoint = entry->base.id;
682 event->data.receive_messagebody.bin = result->data;
683 event->data.receive_messagebody.len = result->len;
685 case HTTP_CONTENTDECODER_RESULTTYPE_NEED_INPUT:
686 entry->rcv_state = RECEIVE_MESSAGE_BODY_TRANSFERDECODE;
688 case HTTP_CONTENTDECODER_RESULTTYPE_END:
689 entry->rcv_state = RECEIVE_MESSAGE_END;
696 LOCAL W http_connector_rcv_message_body_transferdecode(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
698 http_transferdecoder_result *result;
701 if (entry->rcv_reader.body.transfer_result_consumed == entry->rcv_reader.body.transfer_result_len) {
702 entry->rcv_state = RECEIVE_MESSAGE_BODY;
706 result = entry->rcv_reader.body.transfer_result + entry->rcv_reader.body.transfer_result_consumed;
707 switch (result->type) {
708 case HTTP_TRANSFERDECODER_RESULTTYPE_DATA:
709 err = http_contentdecoder_inputentitybody(&entry->rcv_reader.cc, result->data, result->len);
711 case HTTP_TRANSFERDECODER_RESULTTYPE_END:
712 err = http_contentdecoder_inputendofdata(&entry->rcv_reader.cc);
717 entry->rcv_reader.body.transfer_result_consumed++;
719 DP_ER("http_contentdecoder_inputXXX", err);
722 entry->rcv_state = RECEIVE_MESSAGE_BODY_CONTENTDECODE;
724 return http_connector_rcv_message_body_contentdecode(connector, entry, event);
727 LOCAL W http_connector_rcv_message_body(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
732 err = http_transport_read(connector->transport, entry->transport, &bin, &len);
734 DP_ER("http_transport_read", err);
738 len = http_transferdecoder_inputentitybody(&entry->rcv_reader.tc, bin, len, &entry->rcv_reader.body.transfer_result, &entry->rcv_reader.body.transfer_result_len);
739 entry->rcv_reader.body.transfer_result_consumed = 0;
740 http_transport_consumereadbuffer(connector->transport, entry->transport, len);
742 entry->rcv_state = RECEIVE_MESSAGE_BODY_TRANSFERDECODE;
744 return http_connector_rcv_message_body_transferdecode(connector, entry, event);
747 LOCAL W http_connector_rcv_message_end(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
749 Bool connection_closed;
751 http_contentdecoder_finalize(&entry->rcv_reader.cc);
752 http_transferdecoder_finalize(&entry->rcv_reader.tc);
753 connection_closed = http_defaultheaderparser_connectionclosed(&entry->rcv_reader.dh);
755 entry->status = COMPLETED;
756 entry->rcv_state = RECEIVE_COMPLETED;
757 event->endpoint = entry->base.id;
758 event->type = HTTP_CONNECTOR_EVENTTYPE_RECEIVE_MESSAGEBODY_END;
760 http_reqentry_detachendpoint(entry, connector->transport, connection_closed);
765 LOCAL W http_connector_handleevent_receiving_response(http_connector_t *connector, http_reqentry_t *entry, http_connector_event *event)
769 switch (entry->rcv_state) {
770 case RECEIVE_STATUS_LINE:
771 DP_STATE("RECEIVE_STATUS_LINE");
772 err = http_connector_rcv_status_line(connector, entry, event);
775 DP_STATE("RECEIVE_RECEIVE_HEADER");
776 err = http_connector_rcv_header(connector, entry, event);
778 case RECEIVE_HEADER_END:
779 DP_STATE("RECEIVE_HEADER_END");
780 err = http_connector_rcv_header_end(connector, entry, event);
782 case RECEIVE_MESSAGE_BODY:
783 DP_STATE("RECEIVE_MESSAGE_BODY");
784 err = http_connector_rcv_message_body(connector, entry, event);
786 case RECEIVE_MESSAGE_BODY_TRANSFERDECODE:
787 DP_STATE("RECEIVE_MESSAGE_BODY_TRANSFERDECODE");
788 err = http_connector_rcv_message_body_transferdecode(connector, entry, event);
790 case RECEIVE_MESSAGE_BODY_CONTENTDECODE:
791 DP_STATE("RECEIVE_MESSAGE_BODY_CONTENTDECDE");
792 err = http_connector_rcv_message_body_contentdecode(connector, entry, event);
794 case RECEIVE_MESSAGE_END:
795 DP_STATE("RECEIVE_MESSAGE_END");
796 err = http_connector_rcv_message_end(connector, entry, event);
798 case RECEIVE_COMPLETED:
799 DP_STATE("RECEIVE_COMPLETED");
807 /* TODO: devide event found and need loop for state transition */
808 EXPORT Bool http_connector_searcheventtarget(http_connector_t *connector, http_connector_event *event)
810 http_reqentry_t *entry;
811 http_recdictiterator_t iter;
812 Bool cont, found = False;
815 event->type = HTTP_CONNECTOR_EVENTTYPE_NONE;
817 http_reqdictiterator_initialize(&iter, connector->dict);
819 cont = http_reqdictiterator_next(&iter, &entry);
823 if (entry->status == SENDING_REQUEST) {
824 event->type = HTTP_CONNECTOR_EVENTTYPE_SEND;
825 event->endpoint = entry->base.id;
829 if (entry->status == DETECTING_ERROR) {
830 event->type = HTTP_CONNECTOR_EVENTTYPE_ERROR;
831 event->endpoint = entry->base.id;
832 entry->status = FAILED;
836 if (entry->status == RECEIVING_RESPONSE) {
837 err = http_connector_handleevent_receiving_response(connector, entry, event);
838 if ((err < 0)&&((err & 0xFFFF0000) != EX_WOULDBLOCK)) {
839 event->type = HTTP_CONNECTOR_EVENTTYPE_ERROR;
840 event->endpoint = entry->base.id;
841 entry->status = ABORTED_BY_TRANSPORT;
842 http_reqentry_detachendpoint(entry, connector->transport, True);
852 http_reqdictiterator_finalize(&iter);
857 EXPORT W http_connector_getevent(http_connector_t *connector, http_connector_event *event)
862 err = wai_flg(connector->flg, HTTP_CONNECTOR_FLAG_EVENT, WF_AND|NOCLR, T_NOWAIT);
863 if ((err & 0xFFFF0000) == ER_NONE) {
867 DP_ER("wai_flg", err);
870 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
871 found = http_connector_searcheventtarget(connector, event);
872 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
873 if (found == False) {
874 err = clr_flg(connector->flg, HTTP_CONNECTOR_FLAG_CLEARMASK_EVENT);
876 DP_ER("clr_flg", err);
879 return ER_NONE; /* TODO: detail error code */
881 if (event->type == HTTP_CONNECTOR_EVENTTYPE_NONE) {
882 return ER_NONE; /* TODO: detail error code */
887 #define HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, state, entry) \
888 (entry) = http_reqdict_getentrybyID((connector)->dict, (endpoint)); \
889 if ((entry) == NULL) { \
890 return ER_NOEXS; /* TODO: detail error code */ \
892 if ((entry)->status != SENDING_REQUEST) { \
893 return ER_PAR; /* TODO: suitable error code */ \
895 if ((entry)->snd_state != (state)) { \
896 return ER_PAR; /* TODO: suitable error code */ \
899 #define HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, state1, state2, entry) \
900 (entry) = http_reqdict_getentrybyID((connector)->dict, (endpoint)); \
901 if ((entry) == NULL) { \
902 return ER_NOEXS; /* TODO: detail error code */ \
904 if ((entry)->status != SENDING_REQUEST) { \
905 return ER_PAR; /* TODO: suitable error code */ \
907 if (((entry)->snd_state != (state1))&&((entry)->snd_state != (state2))) { \
908 return ER_PAR; /* TODO: suitable error code */ \
911 EXPORT W http_connector_sendrequestline(http_connector_t *connector, ID endpoint, UB *path, W path_len)
913 http_reqentry_t *entry;
914 http_requestlinestream_t reqline;
919 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
921 HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_REQUEST_LINE, entry);
923 err = http_requestlinestream_initialize(&reqline, entry->method, path, path_len);
925 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
929 cont = http_requestlinestream_make(&reqline, &str, &len);
933 err = http_transport_write(connector->transport, entry->transport, str, len);
938 http_requestlinestream_finalize(&reqline);
941 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
945 entry->snd_state = SEND_HEADER_MINE;
947 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
952 LOCAL W http_connector_writedefaultheader(http_connector_t *connector, ID transport, UB *host, W host_len)
954 http_defaultheaderstream_t defaultheader;
959 http_defaultheaderstream_initialize(&defaultheader, host, host_len);
961 cont = http_defaultheaderstream_make(&defaultheader, &str, &len);
965 err = http_transport_write(connector->transport, transport, str, len);
970 http_defaultheaderstream_finalize(&defaultheader);
975 EXPORT W http_connector_sendheader(http_connector_t *connector, ID endpoint, UB *p, W len)
977 http_reqentry_t *entry;
980 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
982 HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, SEND_HEADER_MINE, SEND_HEADER_USER, entry);
984 if (entry->snd_state == SEND_HEADER_MINE) {
985 err = http_connector_writedefaultheader(connector, entry->transport, entry->host, entry->host_len);
987 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
990 entry->snd_state = SEND_HEADER_USER;
993 err = http_transport_write(connector->transport, entry->transport, p, len);
995 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1000 EXPORT W http_connector_sendheaderend(http_connector_t *connector, ID endpoint)
1002 http_reqentry_t *entry;
1005 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
1007 HTTP_CONNECTOR_SENDXXX_GET_CHECK_2(connector, endpoint, SEND_HEADER_MINE, SEND_HEADER_USER, entry);
1009 if (entry->snd_state == SEND_HEADER_MINE) {
1010 err = http_connector_writedefaultheader(connector, entry->transport, entry->host, entry->host_len);
1012 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1016 err = http_transport_write(connector->transport, entry->transport, "\r\n", 2);
1018 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1022 entry->snd_state = SEND_MESSAGE_BODY;
1024 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1029 EXPORT W http_connector_sendmessagebody(http_connector_t *connector, ID endpoint, UB *p, W len)
1031 http_reqentry_t *entry;
1034 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
1036 HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_MESSAGE_BODY, entry);
1038 err = http_transport_write(connector->transport, entry->transport, p, len);
1039 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1047 EXPORT W http_connector_sendmessagebodyend(http_connector_t *connector, ID endpoint)
1049 http_reqentry_t *entry;
1052 HTTP_CONNECTOR_ENTER_CRITICAL_SECTION_RET_ERR(connector);
1054 HTTP_CONNECTOR_SENDXXX_GET_CHECK(connector, endpoint, SEND_MESSAGE_BODY, entry);
1056 entry->status = WAITING_RESPONSE;
1058 HTTP_CONNECTOR_LEAVE_CRITICAL_SECTION(connector);
1063 EXPORT http_connector_t* http_connector_new()
1065 http_connector_t *connector;
1067 connector = (http_connector_t*)malloc(sizeof(http_connector_t));
1068 if (connector == NULL) {
1072 connector->dict = http_reqdict_new(10/*tmp*/);
1073 if (connector->dict == NULL) {
1074 DP_ER("http_recdict_new", 0);
1075 goto error_http_reqdict;
1077 connector->flg = cre_flg(0, DELEXIT);
1078 if (connector->flg < 0) {
1079 DP_ER("cre_flg", connector->flg);
1082 connector->sem = cre_sem(1, SEM_EXCL|DELEXIT);
1083 if (connector->sem < 0) {
1084 DP_ER("cre_sem", connector->sem);
1087 connector->transport = http_transport_new(10/*tmp*/);
1088 if (connector->transport == NULL) {
1089 DP_ER("http_transport_new", -1);
1090 goto error_transport;
1095 http_transport_delete(connector->transport);
1097 del_sem(connector->sem);
1099 del_flg(connector->flg);
1101 http_reqdict_delete(connector->dict);
1107 EXPORT VOID http_connector_delete(http_connector_t *connector)
1109 http_transport_delete(connector->transport);
1110 del_sem(connector->sem);
1111 del_flg(connector->flg);
1112 http_reqdict_delete(connector->dict);