diff --git a/plugin/protocol/http/src/http_half.cpp b/plugin/protocol/http/src/http_half.cpp index 1634933..2d51271 100644 --- a/plugin/protocol/http/src/http_half.cpp +++ b/plugin/protocol/http/src/http_half.cpp @@ -92,6 +92,19 @@ uint16_t __hf_content_encoding_parse(const char * str_content_encoding) 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) { @@ -444,16 +457,36 @@ const char * hf_ops_field_read(const struct tfe_http_half * half, const struct h return __header_found != NULL ? __header_iter->value : NULL; } -int hf_ops_field_write(struct tfe_http_half * half, const struct http_field_name * name, const char * value) +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 = ALLOC(struct http_header_private, 1); - __header->field = http_field_name_duplicate(name); - __header->value = tfe_strdup(value); + 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; + } + + /* Found a header, update a value, + * or insert a new header k-v in the tail of the header list */ + + if(__header_found != NULL) + { + if (__header_found->value != NULL) free(__header_found->value); + __header_found->value = tfe_strdup(value); + } + else + { + 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); + } - TAILQ_INSERT_TAIL(&hf_private->header_list, __header, next); return 0; } @@ -786,6 +819,30 @@ void hf_private_construct(struct http_half_private * hf_private) 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) + { + /* 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); + } + /* HTTP Request/Response first line */ if (hf_public->direction == TFE_HTTP_REQUEST) __construct_request_line(hf_private); else __construct_response_line(hf_private); @@ -804,12 +861,6 @@ void hf_private_construct(struct http_half_private * hf_private) /* delimitor between header and body */ evbuffer_add_printf(hf_private->evbuf_raw, "\r\n"); - /* 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); - } - /* add body */ if (hf_private->evbuf_body) {