#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" }; 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 (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; } /* 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)); /* 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); } 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 = parser->method; const static struct http_field_name __accept_encoding_field_name = { .field_id = TFE_HTTP_ACCEPT_ENCODING, .field_name = NULL }; const static struct http_field_name __host_field_name = { .field_id = TFE_HTTP_HOST, .field_name = NULL }; hf_req_spec->accept_encoding = (char *)tfe_http_field_read(hf_public, &__accept_encoding_field_name); 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 * url is more complex. need to review RFC */ hf_req_spec->url = NULL; } 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; const static struct http_field_name __cont_encoding_field_name = { .field_id = TFE_HTTP_CONT_ENCODING, .field_name = NULL }; /* Content Encoding */ hf_resp_spec->content_encoding = (char *)tfe_http_field_read(hf_public, &__cont_encoding_field_name); } /* ================================================================================================================== * REQUEST PARSER CALLBACKS * ================================================================================================================== */ static int __parser_callback_on_message_begin(struct http_parser * parser) { struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser); enum tfe_http_direction direction = hf_private->hf_public.direction; 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_uri = evbuffer_new(); hf_private->evbuf_header_field = evbuffer_new(); hf_private->evbuf_header_value = evbuffer_new(); hf_private->evbuf_body = evbuffer_new(); 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); /* Last field-value tuple doesn't push into hf_private, flush these */ if (evbuffer_get_length(hf_private->evbuf_header_field) != 0) { __http_half_header_kv_complete(hf_private); } 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); return evbuffer_add(hf_private->evbuf_header_value, at, length); } 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); return evbuffer_add(hf_private->evbuf_body, 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; 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; 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); } http_parser_pause(parser, 1); return 0; } static int __parser_callback_on_message_complete(http_parser * parser) { struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser); 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 }; 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; /* 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; return hf_private; } void hf_private_destory(struct http_half_private * hf_private) { if (hf_private->parse_object != NULL) free(hf_private->parse_object); free(hf_private); } int hf_private_parse(struct http_half_private * hf_private, const unsigned char * data, size_t len) { assert(hf_private->parse_cursor <= len); int ret = 0; /* 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); /* The paused parsar indicate that some kind of boundary has been touched, * we should return and call user's data callback. resume it to normal status */ if (sz_parsed && HTTP_PARSER_ERRNO(hf_private->parse_object) == HPE_PAUSED) { http_parser_pause(hf_private->parse_object, 0); ret = 1; goto __out; } /* Some kind of exception happend */ if (sz_parsed && HTTP_PARSER_ERRNO(hf_private->parse_object) > 0) { hf_private->parse_errno = HTTP_PARSER_ERRNO(hf_private->parse_object); ret = -1; goto __out; } __out: hf_private->parse_cursor += sz_parsed; return ret; }