create_dissector_handle -> new_create_dissector_handle
[metze/wireshark/wip.git] / epan / dissectors / packet-http.c
index c434c6e5f1b78329fd3592bbdcb5149975bbe7db..03c231bebf4b902d5ac8caa15bf893b34fdbc079 100644 (file)
@@ -62,9 +62,13 @@ static int http_tap = -1;
 static int http_eo_tap = -1;
 
 static int proto_http = -1;
+static int proto_http2 = -1;
+static int proto_ssdp = -1;
 static int hf_http_notification = -1;
 static int hf_http_response = -1;
 static int hf_http_request = -1;
+static int hf_http_response_number = -1;
+static int hf_http_request_number = -1;
 static int hf_http_response_line = -1;
 static int hf_http_request_line = -1;
 static int hf_http_basic = -1;
@@ -119,7 +123,10 @@ static int hf_http_next_response_in = -1;
 static int hf_http_prev_request_in = -1;
 static int hf_http_prev_response_in = -1;
 static int hf_http_time = -1;
+static int hf_http_chunk_size = -1;
+static int hf_http_chunk_boundary = -1;
 static int hf_http_chunked_trailer_part = -1;
+static int hf_http_unknown_header = -1;
 
 static gint ett_http = -1;
 static gint ett_http_ntlmssp = -1;
@@ -142,6 +149,9 @@ static dissector_handle_t data_handle;
 static dissector_handle_t media_handle;
 static dissector_handle_t websocket_handle;
 static dissector_handle_t http2_handle;
+static dissector_handle_t sstp_handle;
+static dissector_handle_t ntlmssp_handle;
+static dissector_handle_t gssapi_handle;
 
 /* Stuff for generation/handling of fields for custom HTTP headers */
 typedef struct _header_field_t {
@@ -154,7 +164,7 @@ static guint num_header_fields = 0;
 
 static GHashTable* header_fields_hash = NULL;
 
-static void
+static gboolean
 header_fields_update_cb(void *r, char **err)
 {
        header_field_t *rec = (header_field_t *)r;
@@ -162,13 +172,13 @@ header_fields_update_cb(void *r, char **err)
 
        if (rec->header_name == NULL) {
                *err = g_strdup("Header name can't be empty");
-               return;
+               return FALSE;
        }
 
        g_strstrip(rec->header_name);
        if (rec->header_name[0] == 0) {
                *err = g_strdup("Header name can't be empty");
-               return;
+               return FALSE;
        }
 
        /* Check for invalid characters (to avoid asserting out when
@@ -177,10 +187,11 @@ header_fields_update_cb(void *r, char **err)
        c = proto_check_field_name(rec->header_name);
        if (c) {
                *err = g_strdup_printf("Header name can't contain '%c'", c);
-               return;
+               return FALSE;
        }
 
        *err = NULL;
+       return TRUE;
 }
 
 static void *
@@ -264,6 +275,7 @@ static gboolean http_decompress_body = FALSE;
 
 #define UPGRADE_WEBSOCKET 1
 #define UPGRADE_HTTP2 2
+#define UPGRADE_SSTP 3
 
 static range_t *global_http_tcp_range = NULL;
 static range_t *global_http_ssl_range = NULL;
@@ -312,9 +324,6 @@ static dissector_table_t port_subdissector_table;
 static dissector_table_t media_type_subdissector_table;
 static heur_dissector_list_t heur_subdissector_list;
 
-static dissector_handle_t ntlmssp_handle;
-static dissector_handle_t gssapi_handle;
-
 /* --- HTTP Status Codes */
 /* Note: The reference for uncommented entries is RFC 2616 */
 static const value_string vals_status_code[] = {
@@ -607,22 +616,21 @@ dissect_http_kerberos(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
 
 static http_conv_t *
-get_http_conversation_data(packet_info *pinfo)
+get_http_conversation_data(packet_info *pinfo, conversation_t **conversation)
 {
-       conversation_t  *conversation;
        http_conv_t     *conv_data;
 
-       conversation = find_or_create_conversation(pinfo);
+       *conversation = find_or_create_conversation(pinfo);
 
        /* Retrieve information from conversation
         * or add it if it isn't there yet
         */
-       conv_data = (http_conv_t *)conversation_get_proto_data(conversation, proto_http);
+       conv_data = (http_conv_t *)conversation_get_proto_data(*conversation, proto_http);
        if(!conv_data) {
                /* Setup the conversation structure itself */
                conv_data = (http_conv_t *)wmem_alloc0(wmem_file_scope(), sizeof(http_conv_t));
 
-               conversation_add_proto_data(conversation, proto_http,
+               conversation_add_proto_data(*conversation, proto_http,
                                            conv_data);
        }
 
@@ -691,9 +699,8 @@ static http_info_value_t    *stat_info;
 
 static int
 dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
-                    proto_tree *tree, http_conv_t *conv_data)
+                    proto_tree *tree, http_conv_t *conv_data, const char* proto_tag, int proto)
 {
-       const char      *proto_tag;
        proto_tree      *http_tree = NULL;
        proto_item      *ti = NULL;
        proto_item      *hidden_item;
@@ -818,17 +825,6 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
        stat_info->request_uri = NULL;
        stat_info->http_host = NULL;
 
-       switch (pinfo->match_uint) {
-
-       case TCP_PORT_SSDP:     /* TCP_PORT_SSDP = UDP_PORT_SSDP */
-               proto_tag = "SSDP";
-               break;
-
-       default:
-               proto_tag = "HTTP";
-               break;
-       }
-
        orig_offset = offset;
 
        /*
@@ -843,7 +839,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
        headers.transfer_encoding = NULL; /* transfer encoding not known yet */
        headers.upgrade = 0; /* assume we're not upgrading */
        saw_req_resp_or_header = FALSE; /* haven't seen anything yet */
-       while (tvb_reported_length_remaining(tvb, offset) > 0) {
+       while (tvb_offset_exists(tvb, offset)) {
                /*
                 * Find the end of the line.
                 * XXX - what if we don't find it because the packet
@@ -1003,7 +999,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
                }
 
                if ((tree) && (http_tree == NULL)) {
-                       ti = proto_tree_add_item(tree, proto_http, tvb, orig_offset, -1, ENC_NA);
+                       ti = proto_tree_add_item(tree, proto, tvb, orig_offset, -1, ENC_NA);
                        http_tree = proto_item_add_subtree(ti, ett_http);
                        if(leading_crlf){
                                proto_tree_add_expert(http_tree, pinfo, &ei_http_leading_crlf, tvb, orig_offset-2, 2);
@@ -1105,7 +1101,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
                        if (curr) {
                                nstime_t delta;
 
-                               pi = proto_tree_add_text(http_tree, tvb, 0, 0, "HTTP response %u/%u", curr->number, conv_data->req_res_num);
+                               pi = proto_tree_add_uint_format(http_tree, hf_http_response_number, tvb, 0, 0, curr->number, "HTTP response %u/%u", curr->number, conv_data->req_res_num);
                                PROTO_ITEM_SET_GENERATED(pi);
 
                                if (! nstime_is_unset(&(curr->req_ts))) {
@@ -1143,7 +1139,7 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
                        PROTO_ITEM_SET_HIDDEN(hidden_item);
 
                        if (curr) {
-                               pi = proto_tree_add_text(http_tree, tvb, 0, 0, "HTTP request %u/%u", curr->number, conv_data->req_res_num);
+                               pi = proto_tree_add_uint_format(http_tree, hf_http_request_number, tvb, 0, 0, curr->number, "HTTP request %u/%u", curr->number, conv_data->req_res_num);
                                PROTO_ITEM_SET_GENERATED(pi);
                        }
                        if (prev && prev->req_framenum) {
@@ -1517,10 +1513,15 @@ dissect_http_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
                offset += datalen;
        }
 
+       if (http_type == HTTP_RESPONSE && conv_data->upgrade == UPGRADE_SSTP) {
+               conv_data->startframe = pinfo->fd->num + 1;
+               headers.upgrade = conv_data->upgrade;
+       }
+
        if (http_type == HTTP_RESPONSE && pinfo->desegment_offset<=0 && pinfo->desegment_len<=0) {
                conv_data->upgrade = headers.upgrade;
                conv_data->startframe = pinfo->fd->num + 1;
-               SE_COPY_ADDRESS(&conv_data->server_addr, &pinfo->src);
+               copy_address_wmem(wmem_file_scope(), &conv_data->server_addr, &pinfo->src);
                conv_data->server_port = pinfo->srcport;
        }
 
@@ -1630,7 +1631,7 @@ basic_response_dissector(tvbuff_t *tvb, proto_tree *tree, int offset,
 
 }
 
-#if 0 /* XXX: Replaced by code creating the "Dechunked" tvb  O(N) rather tan O(N^2) */
+#if 0 /* XXX: Replaced by code creating the "Dechunked" tvb O(N) rather than O(N^2) */
 /*
  * Dissect the http data chunks and add them to the tree.
  */
@@ -1662,7 +1663,7 @@ chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
                                         ett_http_chunked_response, NULL, "HTTP chunked response");
 
        while (datalen > 0) {
-               proto_item *chunk_ti = NULL;
+               proto_item *chunk_ti = NULL, *chuck_size_item;
                proto_tree *chunk_subtree = NULL;
                tvbuff_t *data_tvb = NULL; /*  */
                gchar *c = NULL;
@@ -1756,25 +1757,24 @@ chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
                                            ett_http_chunk_data, NULL, "Data chunk (%u octets)", chunk_size);
                        }
 
-                       proto_tree_add_text(chunk_subtree, tvb, offset,
-                           chunk_offset - offset, "Chunk size: %u octets",
-                           chunk_size);
-
-                       data_tvb = tvb_new_subset_length(tvb, chunk_offset, chunk_size);
-
+                       chuck_size_item = proto_tree_add_uint_format_value(chunk_subtree, hf_http_chunk_size, tvb, offset,
+                           1, chunk_size, "%u octets", chunk_size);
+                       proto_item_set_len(chuck_size_item, chunk_offset - offset);
 
                        /*
-                        * XXX - just use "proto_tree_add_text()"?
-                        * This means that, in TShark, you get
-                        * the entire chunk dumped out in hex,
-                        * in addition to whatever dissection is
-                        * done on the reassembled data.
+                        * XXX - just add the chunk's data as an item?
+                        *
+                        * Using the data dissector means that, in
+                        * TShark, you get the entire chunk dumped
+                        * out in hex, in addition to whatever
+                        * dissection is done on the reassembled data.
                         */
+                       data_tvb = tvb_new_subset_length(tvb, chunk_offset, chunk_size);
                        call_dissector(data_handle, data_tvb, pinfo,
                                    chunk_subtree);
 
-                       proto_tree_add_text(chunk_subtree, tvb, chunk_offset +
-                           chunk_size, 2, "Chunk boundary");
+                       proto_tree_add_item(chunk_subtree, hf_http_chunked_boundary, tvb,
+                                                               chunk_offset + chunk_size, 2, ENC_NA);
                }
 
                chunks_decoded++;
@@ -1894,6 +1894,7 @@ chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
 
                if (subtree) {
                        proto_tree *chunk_subtree;
+                       proto_item *chunk_size_item;
 
                        if(chunk_size == 0) {
                                chunk_subtree = proto_tree_add_subtree(subtree, tvb,
@@ -1909,26 +1910,26 @@ chunked_encoding_dissector(tvbuff_t **tvb_ptr, packet_info *pinfo,
                                            "Data chunk (%u octets)", chunk_size);
                        }
 
-                       proto_tree_add_text(chunk_subtree, tvb, offset,
-                           chunk_offset - offset, "Chunk size: %u octets",
-                           chunk_size);
+                       chunk_size_item = proto_tree_add_uint_format_value(chunk_subtree, hf_http_chunk_size, tvb, offset,
+                           1, chunk_size, "%u octets", chunk_size);
+                       proto_item_set_len(chunk_size_item, chunk_offset - offset);
 
                        /* last-chunk does not have chunk-data CRLF. */
                        if (chunk_size > 0) {
-                               data_tvb = tvb_new_subset(tvb, chunk_offset, chunk_size, datalen);
-
                                /*
-                                * XXX - just use "proto_tree_add_text()"?
-                                * This means that, in TShark, you get
-                                * the entire chunk dumped out in hex,
-                                * in addition to whatever dissection is
-                                * done on the reassembled data.
+                                * XXX - just add the chunk's data as an item?
+                                *
+                                * Using the data dissector means that, in
+                                * TShark, you get the entire chunk dumped
+                                * out in hex, in addition to whatever
+                                * dissection is done on the reassembled data.
                                 */
+                               data_tvb = tvb_new_subset_length(tvb, chunk_offset, chunk_size);
                                call_dissector(data_handle, data_tvb, pinfo,
                                            chunk_subtree);
 
-                               proto_tree_add_text(chunk_subtree, tvb, chunk_offset +
-                                   chunk_size, 2, "Chunk boundary");
+                               proto_tree_add_item(chunk_subtree, hf_http_chunk_boundary, tvb,
+                                                                       chunk_offset + chunk_size, 2, ENC_NA);
                        }
                }
 
@@ -2034,7 +2035,7 @@ http_payload_subdissector(tvbuff_t *tvb, proto_tree *tree,
                 * conversation (e.g., one we detected heuristically or via Decode-As) call the data
                 * dissector directly.
                 */
-               if (value_is_in_range(http_tcp_range, uri_port) || (conv && conv->dissector_handle == http_handle)) {
+               if (value_is_in_range(http_tcp_range, uri_port) || (conv && conversation_get_dissector(conv, pinfo->fd->num) == http_handle)) {
                        call_dissector(data_handle, tvb, pinfo, tree);
                } else {
                        /* set pinfo->{src/dst port} and call the TCP sub-dissector lookup */
@@ -2143,6 +2144,7 @@ is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
                                strncmp(data, "BMOVE", indx) == 0 ||
                                strncmp(data, "MKCOL", indx) == 0 ||
                                strncmp(data, "TRACE", indx) == 0 ||
+                               strncmp(data, "PATCH", indx) == 0 ||  /* RFC 5789 */
                                strncmp(data, "LABEL", indx) == 0 ||  /* RFC 3253 8.2 */
                                strncmp(data, "MERGE", indx) == 0) {  /* RFC 3253 11.2 */
                                *type = HTTP_REQUEST;
@@ -2234,6 +2236,10 @@ is_http_request_or_reply(const gchar *data, int linelen, http_type_t *type,
                        if (strncmp(data, "BASELINE-CONTROL", indx) == 0) {  /* RFC 3253 12.6 */
                                *type = HTTP_REQUEST;
                                isHttpRequestOrReply = TRUE;
+                       } else if (strncmp(data, "SSTP_DUPLEX_POST", indx) == 0) {  /* MS SSTP */
+                               *type = HTTP_REQUEST;
+                               isHttpRequestOrReply = TRUE;
+                               conv_data->upgrade = UPGRADE_SSTP;
                        }
                        break;
 
@@ -2337,9 +2343,9 @@ header_fields_initialize_cb(void)
 
        if (header_fields_hash && hf) {
                guint hf_size = g_hash_table_size (header_fields_hash);
-               /* Unregister all fields */
+               /* Deregister all fields */
                for (i = 0; i < hf_size; i++) {
-                       proto_unregister_field (proto_http, *(hf[i].p_id));
+                       proto_deregister_field (proto_http, *(hf[i].p_id));
                        g_free (hf[i].p_id);
                }
                g_hash_table_destroy (header_fields_hash);
@@ -2420,7 +2426,9 @@ process_header(tvbuff_t *tvb, int offset, int next_offset,
         * has value_len bytes in it.
         */
        value_len = line_end_offset - value_offset;
-       value = wmem_strndup(wmem_packet_scope(), &line[value_offset - offset], value_len);
+       value = (char *)wmem_alloc(wmem_packet_scope(), value_len+1);
+       memcpy(value, &line[value_offset - offset], value_len);
+       value[value_len] = '\0';
 
        if (hf_index == -1) {
                /*
@@ -2442,8 +2450,9 @@ process_header(tvbuff_t *tvb, int offset, int next_offset,
                                        proto_item_set_text(it, "%s",
                                                        format_text(line, len));
                                } else {
-                                       proto_tree_add_text(tree, tvb, offset,
-                                               len, "%s", format_text(line, len));
+                                       gchar* str = format_text(line, len);
+                                       proto_tree_add_string_format(tree, hf_http_unknown_header, tvb, offset,
+                                               len, str, "%s", str);
                                }
 
                        } else {
@@ -2630,7 +2639,7 @@ process_header(tvbuff_t *tvb, int offset, int next_offset,
                        break;
 
                case HDR_UPGRADE:
-                       if (g_ascii_strncasecmp(value, "WebSocket", value_len) == 0){
+                       if (g_ascii_strncasecmp(value, "WebSocket", value_len) == 0) {
                                eh_ptr->upgrade = UPGRADE_WEBSOCKET;
                        }
                        /* Check if upgrade is HTTP 2.0 (Start with h2...) */
@@ -2880,12 +2889,23 @@ dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
        http_conv_t     *conv_data;
        int             offset = 0;
        int             len;
+       conversation_t *conversation;
+       dissector_handle_t next_handle = NULL;
+
+       conv_data = get_http_conversation_data(pinfo, &conversation);
+       /* Call HTTP2 dissector directly when detected via heuristics, but not
+        * when it was upgraded (the conversation started with HTTP). */
+       if (conversation_get_proto_data(conversation, proto_http2) &&
+           conv_data->upgrade != UPGRADE_HTTP2) {
+               if (pinfo->can_desegment > 0)
+                       pinfo->can_desegment++;
+               return call_dissector_only(http2_handle, tvb, pinfo, tree, NULL);
+       }
 
        /*
         * Check if this is proxied connection and if so, hand of dissection to the
         * payload-dissector.
         * Response code 200 means "OK" and strncmp() == 0 means the strings match exactly */
-       conv_data = get_http_conversation_data(pinfo);
        if(pinfo->fd->num >= conv_data->startframe &&
           conv_data->response_code == 200 &&
           conv_data->request_method &&
@@ -2897,14 +2917,26 @@ dissect_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
        } else {
                while (tvb_reported_length_remaining(tvb, offset) > 0) {
                        if (conv_data->upgrade == UPGRADE_WEBSOCKET && pinfo->fd->num >= conv_data->startframe) {
-                               call_dissector_only(websocket_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree, NULL);
-                               break;
+                               next_handle = websocket_handle;
                        }
                        if (conv_data->upgrade == UPGRADE_HTTP2 && pinfo->fd->num >= conv_data->startframe) {
-                               call_dissector_only(http2_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree, NULL);
+                               next_handle = http2_handle;
+                       }
+                       if (conv_data->upgrade == UPGRADE_SSTP && conv_data->response_code == 200 && pinfo->fd->num >= conv_data->startframe) {
+                               next_handle = sstp_handle;
+                       }
+                       if (next_handle) {
+                               /* Increase pinfo->can_desegment because we are traversing
+                                * http and want to preserve desegmentation functionality for
+                                * the proxied protocol
+                                */
+                               if (pinfo->can_desegment > 0)
+                                       pinfo->can_desegment++;
+
+                               call_dissector_only(next_handle, tvb_new_subset_remaining(tvb, offset), pinfo, tree, NULL);
                                break;
                        }
-                       len = dissect_http_message(tvb, offset, pinfo, tree, conv_data);
+                       len = dissect_http_message(tvb, offset, pinfo, tree, conv_data, "HTTP", proto_http);
                        if (len == -1)
                                break;
                        offset += len;
@@ -2950,24 +2982,25 @@ dissect_http_heur_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
        return FALSE;
 }
 
-static void
-dissect_http_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+static int
+dissect_ssdp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
 {
+       conversation_t  *conversation;
        http_conv_t     *conv_data;
 
-       conv_data = get_http_conversation_data(pinfo);
-       dissect_http_message(tvb, 0, pinfo, tree, conv_data);
+       conv_data = get_http_conversation_data(pinfo, &conversation);
+       dissect_http_message(tvb, 0, pinfo, tree, conv_data, "SSDP", proto_ssdp);
+       return tvb_captured_length(tvb);
 }
 
-
 static void
 range_delete_http_ssl_callback(guint32 port) {
-       ssl_dissector_delete(port, "http", TRUE);
+       ssl_dissector_delete(port, http_handle);
 }
 
 static void
 range_add_http_ssl_callback(guint32 port) {
-       ssl_dissector_add(port, "http", TRUE);
+       ssl_dissector_add(port, http_handle);
 }
 
 static void reinit_http(void) {
@@ -2998,6 +3031,14 @@ proto_register_http(void)
              { "Request",              "http.request",
                FT_BOOLEAN, BASE_NONE, NULL, 0x0,
                "TRUE if HTTP request", HFILL }},
+           { &hf_http_response_number,
+             { "Response number",              "http.response_number",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
+           { &hf_http_request_number,
+             { "Request number",               "http.request_number",
+               FT_UINT32, BASE_DEC, NULL, 0x0,
+               NULL, HFILL }},
            { &hf_http_basic,
              { "Credentials",          "http.authbasic",
                FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
@@ -3206,11 +3247,23 @@ proto_register_http(void)
            { &hf_http_time,
              { "Time since request", "http.time",
                FT_RELATIVE_TIME, BASE_NONE, NULL, 0,
-               "Time since the request was send", HFILL }},
+               "Time since the request was sent", HFILL }},
            { &hf_http_chunked_trailer_part,
              { "trailer-part", "http.chunked_trailer_part",
                FT_STRING, BASE_NONE, NULL, 0,
                "Optional trailer in a chunked body", HFILL }},
+           { &hf_http_chunk_boundary,
+             { "Chunk boundary", "http.chunk_boundary",
+               FT_BYTES, BASE_NONE, NULL, 0,
+               NULL, HFILL }},
+           { &hf_http_chunk_size,
+             { "Chunk size", "http.chunk_size",
+        FT_UINT32, BASE_DEC, NULL, 0,
+               NULL, HFILL }},
+           { &hf_http_unknown_header,
+             { "Unknown header", "http.unknown_header",
+               FT_STRING, BASE_NONE, NULL, 0,
+               NULL, HFILL }},
        };
        static gint *ett[] = {
                &ett_http,
@@ -3242,8 +3295,9 @@ proto_register_http(void)
        expert_module_t* expert_http;
        uat_t* headers_uat;
 
-       proto_http = proto_register_protocol("Hypertext Transfer Protocol",
-           "HTTP", "http");
+       proto_http = proto_register_protocol("Hypertext Transfer Protocol", "HTTP", "http");
+       proto_ssdp = proto_register_protocol("Simple Service Discovery Protocol", "SSDP", "ssdp");
+
        proto_register_field_array(proto_http, hf, array_length(hf));
        proto_register_subtree_array(ett, array_length(ett));
        expert_http = expert_register_protocol(proto_http);
@@ -3294,7 +3348,7 @@ proto_register_http(void)
                                        "SSL/TLS Ports range",
                                        &global_http_ssl_range, 65535);
        /* UAT */
-       headers_uat = uat_new("Custom HTTP headers fields Table",
+       headers_uat = uat_new("Custom HTTP Header Fields",
                              sizeof(header_field_t),
                              "custom_http_header_fields",
                              TRUE,
@@ -3311,7 +3365,7 @@ proto_register_http(void)
                              custom_header_uat_fields
        );
 
-       prefs_register_uat_preference(http_module, "custom_http_header_fields", "Custom HTTP headers fields",
+       prefs_register_uat_preference(http_module, "custom_http_header_fields", "Custom HTTP header fields",
            "A table to define custom HTTP header for which fields can be setup and used for filtering/data extraction etc.",
           headers_uat);
 
@@ -3325,7 +3379,7 @@ proto_register_http(void)
         * HTTP on a specific non-HTTP port.
         */
        port_subdissector_table = register_dissector_table("http.port",
-           "TCP port for protocols using HTTP", FT_UINT16, BASE_DEC);
+           "TCP port for protocols using HTTP", FT_UINT16, BASE_DEC, DISSECTOR_TABLE_NOT_ALLOW_DUPLICATE);
 
        /*
         * Dissectors can register themselves in this table.
@@ -3334,7 +3388,7 @@ proto_register_http(void)
         */
        media_type_subdissector_table =
            register_dissector_table("media_type",
-               "Internet media type", FT_STRING, BASE_NONE);
+               "Internet media type", FT_STRING, BASE_NONE, DISSECTOR_TABLE_ALLOW_DUPLICATE);
 
        /*
         * Heuristic dissectors SHOULD register themselves in
@@ -3382,7 +3436,7 @@ http_port_add(guint32 port)
 void
 proto_reg_handoff_http(void)
 {
-       dissector_handle_t http_udp_handle;
+       dissector_handle_t ssdp_handle;
 
        data_handle = find_dissector("data");
        media_handle = find_dissector("media");
@@ -3392,11 +3446,12 @@ proto_reg_handoff_http(void)
         * XXX - is there anything to dissect in the body of an SSDP
         * request or reply?  I.e., should there be an SSDP dissector?
         */
-       http_udp_handle = create_dissector_handle(dissect_http_udp, proto_http);
-       dissector_add_uint("udp.port", UDP_PORT_SSDP, http_udp_handle);
+       ssdp_handle = new_create_dissector_handle(dissect_ssdp, proto_ssdp);
+       dissector_add_uint("udp.port", UDP_PORT_SSDP, ssdp_handle);
 
        ntlmssp_handle = find_dissector("ntlmssp");
        gssapi_handle = find_dissector("gssapi");
+       sstp_handle = find_dissector("sstp");
 
        stats_tree_register("http", "http",     "HTTP/Packet Counter",   0, http_stats_tree_packet,      http_stats_tree_init, NULL );
        stats_tree_register("http", "http_req", "HTTP/Requests",         0, http_req_stats_tree_packet,  http_req_stats_tree_init, NULL );
@@ -3411,8 +3466,8 @@ proto_reg_handoff_http(void)
 static gint proto_message_http = -1;
 static gint ett_message_http = -1;
 
-static void
-dissect_message_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+static int
+dissect_message_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
 {
        proto_tree      *subtree;
        proto_item      *ti;
@@ -3424,17 +3479,17 @@ dissect_message_http(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                ti = proto_tree_add_item(tree, proto_message_http,
                                tvb, 0, -1, ENC_NA);
                subtree = proto_item_add_subtree(ti, ett_message_http);
-               while (tvb_reported_length_remaining(tvb, offset) > 0) {
+               while (tvb_offset_exists(tvb, offset)) {
                        len = tvb_find_line_end(tvb, offset,
                                        tvb_ensure_captured_length_remaining(tvb, offset),
                                        &next_offset, FALSE);
                        if (len == -1)
                                break;
-                       proto_tree_add_text(subtree, tvb, offset, next_offset - offset,
-                                       "%s", tvb_format_text(tvb, offset, len));
+                       proto_tree_add_format_text(subtree, tvb, offset, len);
                        offset = next_offset;
                }
        }
+       return tvb_captured_length(tvb);
 }
 
 void
@@ -3457,13 +3512,14 @@ proto_reg_handoff_message_http(void)
 {
        dissector_handle_t message_http_handle;
 
-       message_http_handle = create_dissector_handle(dissect_message_http,
+       message_http_handle = new_create_dissector_handle(dissect_message_http,
                        proto_message_http);
 
        dissector_add_string("media_type", "message/http", message_http_handle);
 
-       heur_dissector_add("tcp", dissect_http_heur_tcp, proto_http);
+       heur_dissector_add("tcp", dissect_http_heur_tcp, "HTTP over TCP", "http_tcp", proto_http, HEURISTIC_ENABLE);
 
+       proto_http2 = proto_get_id_by_filter_name("http2");
 
        reinit_http();
 }