#include #include #include #include #include #include #include #include #include #include #include #include #define __PARSER_TO_HF_PRIVATE(_parser) ((struct http_half_private *)(_parser->data)) static const char * __str_std_header_field_map[] = { [TFE_HTTP_UNKNOWN_FIELD] = NULL, [TFE_HTTP_HOST] = "Host", [TFE_HTTP_REFERER] = "Referer", [TFE_HTTP_USER_AGENT] = "User-Agent", [TFE_HTTP_COOKIE] = "Cookie", [TFE_HTTP_PROXY_AUTHORIZATION] = "Proxy-Authorization", [TFE_HTTP_AUTHORIZATION] = "Authorization", [TFE_HTTP_LOCATION] = "Location", [TFE_HTTP_SERVER] = "Server", [TFE_HTTP_ETAG] = "Etag", [TFE_HTTP_DATE] = "Date", [TFE_HTTP_TRAILER] = "Trailer", [TFE_HTTP_TRANSFER_ENCODING] = "Transfer-Encoding", [TFE_HTTP_VIA] = "Via", [TFE_HTTP_PRAGMA] = "Pragma", [TFE_HTTP_CONNECTION] = "Connection", [TFE_HTTP_CONT_ENCODING] = "Content-Encoding", [TFE_HTTP_CONT_LANGUAGE] = "Content-Language", [TFE_HTTP_CONT_LOCATION] = "Content-Location", [TFE_HTTP_CONT_RANGE] = "Content-Range", [TFE_HTTP_CONT_LENGTH] = "Content-Length", [TFE_HTTP_CONT_TYPE] = "Content-Type", [TFE_HTTP_CONT_DISPOSITION] = "Content-Disposition", [TFE_HTTP_EXPIRES] = "Expires", [TFE_HTTP_ACCEPT_ENCODING] = "Accept-Encoding", [TFE_HTTP_CACHE_CONTROL] = "Cache-Control", [TFE_HTTP_IF_MATCH] = "If-Match", [TFE_HTTP_IF_NONE_MATCH] = "If-None-Match", [TFE_HTTP_IF_MODIFIED_SINCE] = "If-Modified-Since", [TFE_HTTP_IF_UNMODIFIED_SINCE] = "If-Unmodified-Since", [TFE_HTTP_LAST_MODIFIED] = "Last-Modified" }; static enum tfe_http_std_field __str_header_field_to_std_field_id(const char * str_field, size_t len) { /* TODO: store the header text in hash table or rbtree, or use AC multistring search algo. */ for (unsigned int i = 0; i < TFE_DIM(__str_std_header_field_map); i++) { const char * __std_header_field = __str_std_header_field_map[i]; if (__std_header_field == NULL) continue; size_t __compare_length = MIN(strlen(__std_header_field), len); if (evutil_ascii_strncasecmp(__std_header_field, str_field, __compare_length) != 0) continue; return (enum tfe_http_std_field) i; } return TFE_HTTP_UNKNOWN_FIELD; } uint16_t __hf_content_encoding_parse(const char * str_content_encoding) { if (strcasestr(str_content_encoding, "gzip") != NULL) { return HTTP_ACCEPT_ENCODING_GZIP; } if (strcasestr(str_content_encoding, "x-gzip") != NULL) { return HTTP_ACCEPT_ENCODING_X_GZIP; } if (strcasestr(str_content_encoding, "deflate") != NULL) { return HTTP_ACCEPT_ENCODING_DEFLATE; } if (strcasestr(str_content_encoding, "bzip2") != NULL) { return HTTP_ACCEPT_ENCODING_BZIP2; } if (strcasestr(str_content_encoding, "x-bzip2") != NULL) { return HTTP_ACCEPT_ENCODING_X_BZIP2; } return HTTP_ACCEPT_ENCODING_NONE; } const char * __hf_content_encoding_to_str(unsigned int encode) { switch (encode) { case HTTP_ACCEPT_ENCODING_GZIP: return "gzip"; case HTTP_ACCEPT_ENCODING_X_GZIP: return "x-gzip"; case HTTP_ACCEPT_ENCODING_DEFLATE: return "deflate"; case HTTP_ACCEPT_ENCODING_BZIP2: return "bzip2"; case HTTP_ACCEPT_ENCODING_X_BZIP2: return "x-bzip2"; default: return ""; } } /* To flush header field and value which stash in evbuffer */ static void __http_half_header_kv_complete(struct http_half_private * hf_private) { size_t sz_evbuf_field = evbuffer_get_length(hf_private->evbuf_header_field); size_t sz_evbuf_value = evbuffer_get_length(hf_private->evbuf_header_value); enum tfe_http_std_field std_field_id; struct http_field_name compact_field; static const char __zero = 0; const char * str_field; const char * str_value; /* No header field or length of header field is zero, ignore this field-value pair. */ if (evbuffer_get_length(hf_private->evbuf_header_field) == 0) { goto __clear_buffer; } /* Write a '\0' for evbuffers */ evbuffer_add(hf_private->evbuf_header_field, &__zero, sizeof(__zero)); evbuffer_add(hf_private->evbuf_header_value, &__zero, sizeof(__zero)); sz_evbuf_field = evbuffer_get_length(hf_private->evbuf_header_field); sz_evbuf_value = evbuffer_get_length(hf_private->evbuf_header_value); /* Convert evbuffer to const char * pair */ str_field = (const char *) evbuffer_pullup(hf_private->evbuf_header_field, sz_evbuf_field); str_value = (const char *) evbuffer_pullup(hf_private->evbuf_header_value, sz_evbuf_value); std_field_id = __str_header_field_to_std_field_id(str_field, sz_evbuf_field); if (std_field_id != TFE_HTTP_UNKNOWN_FIELD) { compact_field.field_id = std_field_id; compact_field.field_name = NULL; } else { compact_field.field_id = TFE_HTTP_UNKNOWN_FIELD; compact_field.field_name = (char *) str_field; } tfe_http_field_write(&hf_private->hf_public, &compact_field, str_value); goto __clear_buffer; __clear_buffer: evbuffer_drain(hf_private->evbuf_header_field, sz_evbuf_field); evbuffer_drain(hf_private->evbuf_header_value, sz_evbuf_value); hf_private->is_evbuf_header_value_set = false; hf_private->is_evbuf_header_field_set = false; } void __hf_public_req_fill_from_private(struct http_half_private * hf_private, struct http_parser * parser) { struct tfe_http_half * hf_public = &hf_private->hf_public; struct tfe_http_req_spec * hf_req_spec = &hf_public->req_spec; /* accept-encoding, host is located in header's K-V structure */ hf_req_spec->method = (enum tfe_http_std_method) parser->method; const static struct http_field_name __host_field_name = {TFE_HTTP_HOST, NULL}; hf_req_spec->host = (char *) tfe_http_field_read(hf_public, &__host_field_name); /* uri is stored in underlay evbuffer, we need to append a terminal zero */ static const char __zero = 0; evbuffer_add(hf_private->evbuf_uri, &__zero, sizeof(__zero)); hf_req_spec->uri = (char *) evbuffer_pullup(hf_private->evbuf_uri, evbuffer_get_length(hf_private->evbuf_uri)); /* TODO: url is more complex. need to review RFC */ if (hf_req_spec->uri[0] != '\0' && hf_req_spec->uri[0] != '/') { asprintf(&hf_private->url_storage, "%s/%s", hf_req_spec->host, hf_req_spec->uri); } else { asprintf(&hf_private->url_storage, "%s%s", hf_req_spec->host, hf_req_spec->uri); } hf_req_spec->url = hf_private->url_storage; assert(hf_req_spec->url != NULL); /* Accept-Encoding */ const static struct http_field_name __accept_encoding_name = {TFE_HTTP_ACCEPT_ENCODING, NULL}; const char * __str_accept_encoding = tfe_http_field_read(hf_public, &__accept_encoding_name); if (__str_accept_encoding != NULL) { hf_private->accept_content_encoding = __hf_content_encoding_parse(__str_accept_encoding); } else { hf_private->accept_content_encoding = HTTP_ACCEPT_ENCODING_NONE; } } void __hf_public_resp_fill_from_private(struct http_half_private * hf_private, struct http_parser * parser) { struct tfe_http_half * hf_public = &hf_private->hf_public; struct tfe_http_resp_spec * hf_resp_spec = &hf_public->resp_spec; /* Status Code */ hf_resp_spec->resp_code = parser->status_code; /* Content Type */ const static struct http_field_name __cont_encoding_type_name = {TFE_HTTP_CONT_TYPE, NULL}; hf_resp_spec->content_type = (char *) tfe_http_field_read(hf_public, &__cont_encoding_type_name); /* Content Length */ const static struct http_field_name __cont_encoding_length_name = {TFE_HTTP_CONT_LENGTH, NULL}; hf_resp_spec->content_length = (char *) tfe_http_field_read(hf_public, &__cont_encoding_length_name); /* Content Encoding */ const static struct http_field_name __cont_encoding_field_name = {TFE_HTTP_CONT_ENCODING, NULL}; hf_resp_spec->content_encoding = (char *) tfe_http_field_read(hf_public, &__cont_encoding_field_name); if (hf_resp_spec->content_encoding != NULL) { hf_private->content_encoding = __hf_content_encoding_parse(hf_resp_spec->content_encoding); } else { hf_private->content_encoding = HTTP_ACCEPT_ENCODING_NONE; } } /* ================================================================================================================== * REQUEST PARSER CALLBACKS * ================================================================================================================== */ #define __HF_PRIVATE_CHANGE_STATUS(_status, _now, _to) \ do { assert(_status == _now); _status = _to; } while(0) static int __parser_callback_on_message_begin(struct http_parser * parser) { struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser); assert(hf_private->evbuf_uri == NULL && hf_private->evbuf_body == NULL); assert(hf_private->evbuf_header_field == NULL && hf_private->evbuf_header_value == NULL); hf_private->evbuf_header_field = evbuffer_new(); hf_private->evbuf_header_value = evbuffer_new(); hf_private->is_evbuf_header_field_set = false; hf_private->is_evbuf_header_value_set = false; hf_private->evbuf_uri = evbuffer_new(); hf_private->evbuf_body = evbuffer_new(); hf_private->body_status = STATUS_INIT; hf_private->message_status = STATUS_READING; /* Never call user's callback, need to defer data */ hf_private->stream_action = ACTION_DEFER_DATA; return 0; } static int __parser_callback_on_uri_field(struct http_parser * parser, const char * at, size_t length) { struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser); return evbuffer_add(hf_private->evbuf_uri, at, length); } static int __parser_callback_on_header_field(struct http_parser * parser, const char * at, size_t length) { struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser); if (hf_private->is_evbuf_header_field_set && hf_private->is_evbuf_header_value_set) { __http_half_header_kv_complete(hf_private); } hf_private->is_evbuf_header_field_set = true; return evbuffer_add(hf_private->evbuf_header_field, at, length); } static int __parser_callback_on_header_value(struct http_parser * parser, const char * at, size_t length) { struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser); hf_private->is_evbuf_header_value_set = true; return evbuffer_add(hf_private->evbuf_header_value, at, length); } static int __parser_callback_on_headers_complete(http_parser * parser) { struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser); enum tfe_http_direction hf_direction = hf_private->hf_public.direction; struct http_session_private * hs_private = hf_private->session; if (evbuffer_get_length(hf_private->evbuf_header_field) != 0) { __http_half_header_kv_complete(hf_private); } struct tfe_http_half * hf_public = &hf_private->hf_public; hf_public->major_version = parser->http_major; hf_public->minor_version = parser->http_minor; /* Copy version to session */ if (hs_private != NULL) { to_hs_public(hs_private)->major_version = hf_public->major_version; to_hs_public(hs_private)->minor_version = hf_public->minor_version; } if (hf_direction == TFE_HTTP_REQUEST) { __hf_public_req_fill_from_private(hf_private, parser); } else { __hf_public_resp_fill_from_private(hf_private, parser); } tfe_http_event event = (hf_direction == TFE_HTTP_REQUEST) ? EV_HTTP_REQ_HDR : EV_HTTP_RESP_HDR; if (hf_private->event_cb) { hf_private->event_cb(hf_private, event, NULL, 0, hf_private->event_cb_user); } /* The setup of user stream option indicates that the way to handle the request/response has * been decided, we should conform the resolution */ if (hf_private->is_user_stream_action_set) { assert(hf_private->stream_action == ACTION_DEFER_DATA); hf_private->stream_action = hf_private->user_stream_action; } /* user's suspend tag is set, which indicate that the way to handle request/response * cannot be determinate at now, need to defer */ else if (hs_private && hs_private->suspend_tag_user) { /* Pause parser, prevent to parse request/response body, * The body should be parsed after resume() */ http_parser_pause(parser, 1); /* Record the event, this event will be trigger again at resume() */ hs_private->suspend_event = event; /* Suspend must be setup at DEFER status. * The request/response cannot be suspend once any bytes has been forwarded to upstream */ assert(hf_private->stream_action == ACTION_DEFER_DATA); } /* Otherwise, forward the request/response */ else { hf_private->stream_action = ACTION_FORWARD_DATA; } return 0; } static int __parser_callback_on_body(struct http_parser * parser, const char * at, size_t length) { struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser); enum tfe_http_direction hf_direction = hf_private->hf_public.direction; enum tfe_http_event ev_body_begin; enum tfe_http_event ev_body_cont; if (hf_direction == TFE_HTTP_REQUEST) { ev_body_begin = EV_HTTP_REQ_BODY_BEGIN; ev_body_cont = EV_HTTP_REQ_BODY_CONT; } else { ev_body_begin = EV_HTTP_RESP_BODY_BEGIN; ev_body_cont = EV_HTTP_RESP_BODY_CONT; } if (hf_private->body_status == STATUS_INIT && hf_private->event_cb) { /* Create ungzip context */ if (hf_private->content_encoding != HTTP_ACCEPT_ENCODING_NONE) { hf_private->cv_uncompress_object = hf_content_uncompress_create( hf_private->content_encoding, hf_private->event_cb, hf_private->event_cb_user); if (unlikely(hf_private->cv_uncompress_object == NULL)) assert(0); } hf_private->event_cb(hf_private, ev_body_begin, NULL, parser->content_length, hf_private->event_cb_user); hf_private->body_status = STATUS_READING; } int ret = 0; if (hf_private->event_cb && length != 0) { if (hf_private->cv_uncompress_object != NULL) { ret = hf_content_uncompress_write(hf_private->cv_uncompress_object, hf_private, ev_body_cont, (const unsigned char *) at, length); } else { ret = hf_private->event_cb(hf_private, ev_body_cont, (const unsigned char *) at, length, hf_private->event_cb_user); } if (ret < 0) { //TODO: what to do if writter raise an error. assert(0); } } return 0; } static int __parser_callback_on_message_complete(http_parser * parser) { struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser); enum tfe_http_direction hf_direction = hf_private->hf_public.direction; enum tfe_http_event ev_message_end; enum tfe_http_event ev_body_end; if (hf_direction == TFE_HTTP_REQUEST) { ev_message_end = EV_HTTP_REQ_END; ev_body_end = EV_HTTP_REQ_BODY_END; } else { ev_message_end = EV_HTTP_RESP_END; ev_body_end = EV_HTTP_RESP_BODY_END; } if (hf_private->event_cb && hf_private->body_status == STATUS_READING) { hf_private->event_cb(hf_private, ev_body_end, NULL, 0, hf_private->event_cb_user); } if (hf_private->event_cb) { hf_private->event_cb(hf_private, ev_message_end, NULL, 0, hf_private->event_cb_user); } hf_private->body_status = STATUS_COMPLETE; hf_private->message_status = STATUS_COMPLETE; http_parser_pause(parser, 1); return 0; } static http_parser_settings __http_half_parse_setting = { .on_message_begin = __parser_callback_on_message_begin, .on_url = __parser_callback_on_uri_field, .on_status = NULL, .on_header_field = __parser_callback_on_header_field, .on_header_value = __parser_callback_on_header_value, .on_headers_complete = __parser_callback_on_headers_complete, .on_body = __parser_callback_on_body, .on_message_complete = __parser_callback_on_message_complete, .on_chunk_header = NULL, .on_chunk_complete = NULL }; const char * hf_ops_field_read(const struct tfe_http_half * half, const struct http_field_name * field) { const struct http_half_private * hf_private = to_hf_private(half); assert(hf_private->major == 0 || hf_private->major == 1); struct http_header_private * __header_iter = NULL; struct http_header_private * __header_found = NULL; TAILQ_FOREACH(__header_iter, &hf_private->header_list, next) { if (http_field_name_compare(__header_iter->field, field) != 0) continue; __header_found = __header_iter; break; } return __header_found != NULL ? __header_iter->value : NULL; } int hf_ops_field_write(struct tfe_http_half * half, const struct http_field_name * field, const char * value) { struct http_half_private * hf_private = to_hf_private(half); assert(hf_private->major == 0 || hf_private->major == 1); struct http_header_private * __header_iter = NULL; struct http_header_private * __header_found = NULL; TAILQ_FOREACH(__header_iter, &hf_private->header_list, next) { if (http_field_name_compare(__header_iter->field, field) != 0) continue; __header_found = __header_iter; break; } /* Update the value */ if (__header_found != NULL && value != NULL) { free(__header_found->value); __header_found->value = tfe_strdup(value); } /* Delete the key and value */ else if (__header_found != NULL && value == NULL) { TAILQ_REMOVE(&hf_private->header_list, __header_found, next); free(__header_found->value); free(__header_found); } /* Insert a new header k-v in the tail of the header list */ else if (__header_found == NULL && value != NULL) { struct http_header_private * __header = ALLOC(struct http_header_private, 1); __header->field = http_field_name_duplicate(field); __header->value = tfe_strdup(value); TAILQ_INSERT_TAIL(&hf_private->header_list, __header, next); } /* Nothing found, and delete nothing */ else { return -1; } return 0; } struct tfe_http_half * hf_ops_allow_write(const struct tfe_http_half * half) { return (struct tfe_http_half *) half; } const char * hf_ops_field_iterate(const struct tfe_http_half * half, void ** iter, struct http_field_name * field) { struct http_header_private ** __header_iter = (struct http_header_private **) iter; const struct http_half_private * hf_private = to_hf_private(half); if (*__header_iter == NULL) { *__header_iter = TAILQ_FIRST(&hf_private->header_list); } else { *__header_iter = TAILQ_NEXT(*__header_iter, next); } if (*__header_iter == NULL) return NULL; /* Reference of inner data, user should copy it */ field->field_id = (*__header_iter)->field->field_id; field->field_name = (*__header_iter)->field->field_name; return (*__header_iter)->value; } int hf_ops_append_body(struct tfe_http_half * half, char * buff, size_t size, int flag) { struct http_half_private * hf_private = to_hf_private(half); /* Indicate the body is finished */ if (buff == NULL && size == 0) { hf_private->message_status = STATUS_COMPLETE; return 0; } if (hf_private->evbuf_body == NULL) { hf_private->evbuf_body = evbuffer_new(); } int ret = 0; if (hf_private->cv_compress_object) { ret = hf_content_compress_write(hf_private->cv_compress_object, (const unsigned char *) buff, size, hf_private->evbuf_body, 0); } else { ret = evbuffer_add(hf_private->evbuf_body, buff, size); } return ret; } int hf_ops_body_begin(struct tfe_http_half * half, int by_stream) { struct http_half_private * hf_private = to_hf_private(half); assert(hf_private->evbuf_body == NULL); if (by_stream) { /* By stream, we do not support content-encoding for now, * send body directly without compression */ if(hf_private->cv_compress_object != NULL) { hf_content_compress_destroy(hf_private->cv_compress_object); hf_private->cv_compress_object = NULL; } hf_private->content_encoding = HTTP_ACCEPT_ENCODING_NONE; hf_private->is_setup_by_stream = true; } hf_private->evbuf_body = evbuffer_new(); return 0; } int hf_ops_body_data(struct tfe_http_half * half, const unsigned char * data, size_t sz_data) { struct http_half_private * hf_private = to_hf_private(half); struct evbuffer * __tmp_output_buffer = evbuffer_new(); int ret = 0; /* Need to compress output */ if (hf_private->cv_compress_object) { ret = hf_content_compress_write(hf_private->cv_compress_object, data, sz_data, __tmp_output_buffer, 0); } else { ret = evbuffer_add(__tmp_output_buffer, data, sz_data); } if (ret < 0) goto __out; ret = evbuffer_add_buffer(hf_private->evbuf_body, __tmp_output_buffer); /* Have write ctx, should write the body to TCP stream immediately but not to store in evbuf_body */ if (hf_private->write_ctx) { /* Perpare to write data, TODO: write to TCP stream by transfer evbuffer */ const unsigned char * ptr_write_data = evbuffer_pullup(hf_private->evbuf_body, -1); size_t sz_write_data = evbuffer_get_length(hf_private->evbuf_body); assert(ptr_write_data != NULL && sz_write_data >= 0); tfe_stream_write_frag(hf_private->write_ctx, ptr_write_data, sz_write_data); /* Need to drain all data */ evbuffer_drain(hf_private->evbuf_body, sz_write_data); } __out: evbuffer_free(__tmp_output_buffer); return ret; } int hf_ops_body_end(struct tfe_http_half * half) { struct http_half_private * hf_private = to_hf_private(half); if (hf_private->write_ctx) { tfe_stream_write_frag_end(hf_private->write_ctx); hf_private->write_ctx = NULL; } hf_private->body_status = STATUS_COMPLETE; hf_private->message_status = STATUS_COMPLETE; // printf("frag write end, stream = %p, hf_private = %p\n", hf_private->session->hc_private->stream, hf_private); return 0; } void hf_private_destory(struct http_half_private * hf_private) { if (hf_private->parse_object != NULL) { free(hf_private->parse_object); } if (hf_private->event_cb_user_deleter != NULL) { hf_private->event_cb_user_deleter(hf_private->event_cb_user); } free(hf_private); } void hf_ops_free(struct tfe_http_half * half) { return hf_private_destory(to_hf_private(half)); } struct tfe_http_half_ops __http_half_ops = { .ops_http_field_read = hf_ops_field_read, .ops_http_field_write = hf_ops_field_write, .ops_http_allow_write = hf_ops_allow_write, .ops_http_field_iterate = hf_ops_field_iterate, .ops_append_body = hf_ops_append_body, .ops_body_begin = hf_ops_body_begin, .ops_body_data = hf_ops_body_data, .ops_body_end = hf_ops_body_end, .ops_free = hf_ops_free }; struct http_half_private * hf_private_create(tfe_http_direction ht_dir, short major, short minor) { struct http_half_private * hf_private = ALLOC(struct http_half_private, 1); assert(hf_private != NULL && (major == 0 || major == 1) && (minor == 0 || minor == 1)); assert(ht_dir == TFE_HTTP_REQUEST || ht_dir == TFE_HTTP_RESPONSE); /* PUBLIC */ hf_private->hf_public.major_version = major; hf_private->hf_public.minor_version = minor; hf_private->hf_public.direction = ht_dir; hf_private->hf_public.ops = &__http_half_ops; /* PRIVATE */ hf_private->parse_object = (struct http_parser *) malloc(sizeof(struct http_parser)); assert(hf_private->parse_object != NULL); if (ht_dir == TFE_HTTP_REQUEST) { http_parser_init(hf_private->parse_object, HTTP_REQUEST); } else { http_parser_init(hf_private->parse_object, HTTP_RESPONSE); } hf_private->parse_settings = &__http_half_parse_setting; hf_private->parse_object->data = hf_private; hf_private->major = major; hf_private->minor = minor; TAILQ_INIT(&hf_private->header_list); return hf_private; } void hf_private_set_callback(struct http_half_private * hf_private, hf_private_cb * cb, void * user, void (* user_deleter)(void *)) { hf_private->event_cb = cb; hf_private->event_cb_user = user; hf_private->event_cb_user_deleter = user_deleter; } void hf_private_set_session(struct http_half_private * hf_private, struct http_session_private * hs_private) { hf_private->session = hs_private; } int hf_private_parse(struct http_half_private * hf_private, const unsigned char * data, size_t len) { assert(hf_private->parse_cursor <= len); /* Caculate the memory zones to scan. The zone from data to data + cursor has been scaned * at last construct procedure, so we don't need to scan again. */ const char * __data_with_offset = (const char *) TFE_PTR_ADD(data, hf_private->parse_cursor); size_t __len_with_offset = len - hf_private->parse_cursor; /* Scan the memory zone */ size_t sz_parsed = http_parser_execute(hf_private->parse_object, &__http_half_parse_setting, __data_with_offset, __len_with_offset); bool __is_paused = false; if (HTTP_PARSER_ERRNO(hf_private->parse_object) == HPE_PAUSED) { http_parser_pause(hf_private->parse_object, 0); __is_paused = true; } if (sz_parsed == __len_with_offset) { hf_private->parse_cursor += sz_parsed; return __is_paused ? 1 : 0; } /* The paused parsar indicate the message boundary has been touched, we should return. * resume it to normal status */ if (__is_paused) { hf_private->parse_cursor += sz_parsed + 1; return 1; } hf_private->parse_errno = HTTP_PARSER_ERRNO(hf_private->parse_object); assert(hf_private->parse_errno != HPE_OK); return -1; } static struct tfe_http_session * hs_ops_allow_write(const struct tfe_http_session * session) { struct http_session_private * hs_private = to_hs_private((struct tfe_http_session *) session); return http_frame_currect_plugin_preempt(hs_private->ht_frame) == 0 ? (struct tfe_http_session *) session : NULL; } void hs_ops_detach(const struct tfe_http_session * session) { struct http_session_private * hs_private = to_hs_private((struct tfe_http_session *) session); return http_frame_currect_plugin_detach(hs_private->ht_frame); } void hs_ops_drop(struct tfe_http_session * session) {} void hs_ops_suspend(struct tfe_http_session * session) { struct http_session_private * hs_private = to_hs_private(session); hs_private->suspend_tag_user = true; } void hs_ops_resume(struct tfe_http_session * session) { struct http_session_private * hs_private = to_hs_private(session); struct http_connection_private * hc_private = hs_private->hc_private; hs_private->suspend_tag_user = false; tfe_stream_resume(hc_private->stream); } // TODO: change the return type to int, there is something happend where -1 returned. void hs_ops_request_set(struct tfe_http_session * session, struct tfe_http_half * req_user) { struct http_session_private * hs_private = to_hs_private(session); struct http_half_private * hf_in_private = to_hf_request_private(hs_private); struct http_half_private * hf_user_private = to_hf_private(req_user); if (hf_in_private != NULL) { if (hf_in_private->stream_action == ACTION_DEFER_DATA) { hf_in_private->user_stream_action = ACTION_DROP_DATA; hf_in_private->is_user_stream_action_set = true; } else { assert(0); } } assert(hs_private->hf_private_req_user == NULL); hs_private->hf_private_req_user = hf_user_private; } void hs_ops_response_set(struct tfe_http_session * session, struct tfe_http_half * resp) { struct http_half_private * hf_private = to_hf_private(resp); struct http_session_private * hs_private = to_hs_private(session); struct http_half_private * hf_in_private = to_hf_response_private(hs_private); if (hf_in_private != NULL) { if (hf_in_private->stream_action == ACTION_DEFER_DATA) { hf_in_private->user_stream_action = ACTION_DROP_DATA; hf_in_private->is_user_stream_action_set = true; } else { assert(0); } } assert(hs_private->hf_private_resp_user == NULL); hs_private->hf_private_resp_user = hf_private; hf_private->session = hs_private; } struct tfe_http_half * hs_ops_request_create(struct tfe_http_session * session, enum tfe_http_std_method method, const char * uri) { struct http_half_private * hf_req_private = hf_private_create(TFE_HTTP_REQUEST, session->major_version, session->minor_version); hf_req_private->method_or_status = method; hf_req_private->url_storage = tfe_strdup(uri); hf_req_private->is_setup_by_user = true; return to_hf_public(hf_req_private); } struct tfe_http_half * hs_ops_response_create(struct tfe_http_session * session, int resp_code) { struct http_half_private * hf_resp_private = hf_private_create(TFE_HTTP_RESPONSE, session->major_version, session->minor_version); hf_resp_private->method_or_status = resp_code; hf_resp_private->is_setup_by_user = true; /* Inherit from request in currect session */ struct http_session_private * ss_private = to_hs_private(session); struct http_half_private * hf_req_private = to_hf_request_private(ss_private); /* we must send content in encode that client asked, * but dont need to be accordance with upstream server's response */ unsigned int content_encoding = HTTP_ACCEPT_ENCODING_NONE; if (hf_req_private != NULL) { hf_resp_private->content_encoding = hf_req_private->accept_content_encoding; content_encoding = hf_resp_private->content_encoding; } /* Create content compress content */ if (content_encoding != HTTP_ACCEPT_ENCODING_NONE) { hf_resp_private->cv_compress_object = hf_content_compress_create(content_encoding); assert(hf_resp_private->cv_compress_object != NULL); } return to_hf_public(hf_resp_private); } struct tfe_http_session_ops __http_session_ops = { .ops_allow_write = hs_ops_allow_write, .ops_detach = hs_ops_detach, .ops_drop = hs_ops_drop, .ops_suspend = hs_ops_suspend, .ops_resume = hs_ops_resume, .ops_request_set = hs_ops_request_set, .ops_response_set = hs_ops_response_set, .ops_request_create = hs_ops_request_create, .ops_response_create = hs_ops_response_create }; void __construct_request_line(struct http_half_private * hf_private) { enum tfe_http_std_method __std_method = (enum tfe_http_std_method) hf_private->method_or_status; const char * __str_method = http_std_method_to_string(__std_method); if (__str_method == NULL) { __str_method = ""; } evbuffer_add_printf(hf_private->evbuf_raw, "%s %s HTTP/%d.%d\r\n", __str_method, hf_private->url_storage, hf_private->major, hf_private->minor); } void __construct_response_line(struct http_half_private * hf_private) { enum tfe_http_std_status __resp_code = (enum tfe_http_std_status) hf_private->method_or_status; const char * __str_resp_code = http_std_status_to_string(__resp_code); if (__str_resp_code == NULL) { __str_resp_code = ""; } evbuffer_add_printf(hf_private->evbuf_raw, "HTTP/%d.%d %d %s\r\n", hf_private->major, hf_private->minor, __resp_code, __str_resp_code); } void hf_private_construct(struct http_half_private * hf_private) { assert(hf_private->is_setup_by_user); struct tfe_http_half * hf_public = to_hf_public(hf_private); /* Clear the output buffer */ if (hf_private->evbuf_raw == NULL) { hf_private->evbuf_raw = evbuffer_new(); assert(hf_private->evbuf_raw != NULL); } else { size_t __buf_length = evbuffer_get_length(hf_private->evbuf_raw); evbuffer_drain(hf_private->evbuf_raw, __buf_length); } /* Terminal the end of gzip stream */ if (hf_private->evbuf_body && hf_private->cv_compress_object) { hf_content_compress_write(hf_private->cv_compress_object, NULL, 0, hf_private->evbuf_body, 1); } if (hf_private->content_encoding != HTTP_ACCEPT_ENCODING_NONE) { const char * __str_content_encoding = __hf_content_encoding_to_str(hf_private->content_encoding); const static struct http_field_name __cont_encoding_type_name = {TFE_HTTP_CONT_ENCODING, NULL}; tfe_http_field_write(hf_public, &__cont_encoding_type_name, __str_content_encoding); } /* have body, write content-length and content-type */ if (hf_private->evbuf_body && !hf_private->is_setup_by_stream) { /* To string */ char str_sz_evbuf_body[TFE_STRING_MAX]; snprintf(str_sz_evbuf_body, sizeof(str_sz_evbuf_body) - 1, "%lu", evbuffer_get_length(hf_private->evbuf_body)); const static struct http_field_name __cont_encoding_length_name = {TFE_HTTP_CONT_LENGTH, NULL}; tfe_http_field_write(hf_public, &__cont_encoding_length_name, str_sz_evbuf_body); /* If origin is chunked, now delete chunked tag */ const static struct http_field_name __cont_transfer_encoding_name = {TFE_HTTP_TRANSFER_ENCODING, NULL}; tfe_http_field_write(hf_public, &__cont_transfer_encoding_name, NULL); } /* HTTP Request/Response first line */ if (hf_public->direction == TFE_HTTP_REQUEST) __construct_request_line(hf_private); else __construct_response_line(hf_private); /* Headers */ void * iterator = NULL; struct http_field_name field_name{}; for (const char * str_value = tfe_http_field_iterate(hf_public, &iterator, &field_name); str_value != NULL; str_value = tfe_http_field_iterate(hf_public, &iterator, &field_name)) { const char * str_field = http_field_to_string(&field_name); evbuffer_add_printf(hf_private->evbuf_raw, "%s: %s\r\n", str_field, str_value); } /* delimitor between header and body */ evbuffer_add_printf(hf_private->evbuf_raw, "\r\n"); /* add body */ if (hf_private->evbuf_body) { evbuffer_add_buffer(hf_private->evbuf_raw, hf_private->evbuf_body); } return; } struct http_session_private * hs_private_create(struct http_connection_private * hc_private, struct http_half_private * hf_private_req, struct http_half_private * hf_private_resp) { struct http_session_private * __hs_private = ALLOC(struct http_session_private, 1); /* HS-PUBLIC */ __hs_private->hs_public.ops = &__http_session_ops; __hs_private->hs_public.req = hf_private_req != NULL ? to_hf_public(hf_private_req) : NULL; __hs_private->hs_public.resp = hf_private_req != NULL ? to_hf_public(hf_private_resp) : NULL; __hs_private->hs_public.session_id = hc_private->session_id_counter++; /* HS-PRIVATE*/ __hs_private->hc_private = hc_private; return __hs_private; } void __write_access_log(struct http_session_private * hs_private) { /* Prepare to write session access log */ /* Request */ struct http_half_private * request = to_hf_request_private(hs_private); /* Response */ struct http_half_private * response = to_hf_response_private(hs_private); /* Req-Public */ struct tfe_http_req_spec * req_spec = request ? &to_hf_public(request)->req_spec : NULL; /* Resp-Public */ struct tfe_http_resp_spec * resp_spec = response ? &to_hf_public(response)->resp_spec : NULL; /* Method */ const char * __str_method = req_spec ? http_std_method_to_string(req_spec->method) : "-"; /* URL */ const char * __str_url = req_spec ? req_spec->url : "-"; /* Resp code */ char __str_resp_code[TFE_STRING_MAX]; if (resp_spec) { snprintf(__str_resp_code, sizeof(__str_resp_code) - 1, "%d", resp_spec->resp_code); } else { snprintf(__str_resp_code, sizeof(__str_resp_code) - 1, "%s", "-"); } /* Content Type */ const char * __str_cont_type = resp_spec ? resp_spec->content_type : "-"; /* Content Length */ const char * __str_cont_length = resp_spec ? resp_spec->content_length : "-"; /* Content Encoding */ const char * __str_cont_encoding = resp_spec ? resp_spec->content_encoding : "-"; char * __access_log; asprintf(&__access_log, "%s %s %s %s %s %s", __str_method, __str_url, __str_resp_code, __str_cont_type, __str_cont_length, __str_cont_encoding); const struct tfe_stream * stream = hs_private->hc_private->stream; tfe_stream_write_access_log(stream, RLOG_LV_INFO, "%s", __access_log); free(__access_log); } void hs_private_destory(struct http_session_private * hs_private) { __write_access_log(hs_private); free(hs_private); } void hs_private_hf_private_set(struct http_session_private * hs_private, struct http_half_private * hf, enum tfe_http_direction direction) { struct tfe_http_half ** ref_old_half_public; struct http_half_private * old_half_private; if (direction == TFE_HTTP_REQUEST) { ref_old_half_public = &hs_private->hs_public.req; old_half_private = to_hf_private(*ref_old_half_public); } else { ref_old_half_public = &hs_private->hs_public.resp; old_half_private = to_hf_private(*ref_old_half_public); } if (old_half_private != NULL) { hf_private_destory(old_half_private); *ref_old_half_public = to_hf_public(hf); } else { *ref_old_half_public = to_hf_public(hf); } return; } struct http_half_private * hs_private_hf_private_release(struct http_session_private * hs_private, enum tfe_http_direction) { return nullptr; }