khash_t (rspamd_url_hash) *url_set) -> goffset
{
auto is_visible = true, is_block = false;
- goffset next_tag_offset = tag->closing.start,
+ goffset next_tag_offset = tag->closing.end + 1,
initial_dest_offset = hc->parsed.size();
if (tag->id == Tag_BR || tag->id == Tag_HR) {
return next_tag_offset;
}
-static auto
-html_append_tags_content(rspamd_mempool_t *pool,
- const gchar *start, gsize len,
- struct html_content *hc,
- GList **exceptions,
- khash_t (rspamd_url_hash) *url_set) -> void
-{
- html_append_tag_content(pool, start, len, hc, hc->root_tag, exceptions, url_set);
-}
-
static auto
html_process_input(rspamd_mempool_t *pool,
GByteArray *in,
guint obrace = 0, ebrace = 0;
struct rspamd_url *url = nullptr;
gint href_offset = -1;
- struct html_tag *cur_tag = nullptr, cur_closing_tag;
+ struct html_tag *cur_tag = nullptr, *parent_tag = nullptr, cur_closing_tag;
struct tag_content_parser_state content_parser_env;
enum {
return nullptr;
}
- auto *parent = cur_tag;
-
hc->all_tags.emplace_back(std::make_unique<html_tag>());
auto *ntag = hc->all_tags.back().get();
ntag->tag_start = c - start;
ntag->flags = flags;
- if (parent) {
- ntag->parent = parent;
- parent->children.push_back(ntag);
+ if (cur_tag) {
+ parent_tag = cur_tag;
}
- else {
- if (hc->root_tag) {
- ntag->parent = hc->root_tag;
- hc->root_tag->children.push_back(ntag);
- }
- else {
- if (ntag->id == Tag_HTML) {
- hc->root_tag = ntag;
- }
- else {
- /* Insert a fake html tag */
- hc->all_tags.emplace_back(std::make_unique<html_tag>());
- auto *top_tag = hc->all_tags.back().get();
- top_tag->tag_start = 0;
- top_tag->flags = CM_HEAD|FL_VIRTUAL;
- top_tag->id = Tag_HTML;
- top_tag->content_offset = 0;
- top_tag->children.push_back(ntag);
- ntag->parent = top_tag;
- hc->root_tag = top_tag;
- }
- }
+
+ if (flags & FL_XML) {
+ return ntag;
}
return ntag;
if (cur_tag) {
cur_tag->id = Tag_HTML;
+ hc->root_tag = cur_tag;
state = content_before_start;
}
else {
closing = FALSE;
break;
case '!':
- cur_tag = new_tag(FL_XML);
+ cur_tag = new_tag(FL_XML|FL_CLOSED);
if (cur_tag) {
state = sgml_tag;
}
p ++;
break;
case '?':
- cur_tag = new_tag(FL_XML);
+ cur_tag = new_tag(FL_XML|FL_CLOSED);
if (cur_tag) {
state = xml_tag;
}
}
}
hc->tags_seen[cur_tag->id] = true;
+
+ /* Shift to the first unclosed tag */
+ while (parent_tag && (parent_tag->flags & FL_CLOSED)) {
+ parent_tag = parent_tag->parent;
+ }
+
+ if (parent_tag) {
+ cur_tag->parent = parent_tag;
+ parent_tag->children.push_back(cur_tag);
+ }
+ else {
+ if (hc->root_tag) {
+ cur_tag->parent = hc->root_tag;
+ hc->root_tag->children.push_back(cur_tag);
+ parent_tag = hc->root_tag;
+ }
+ else {
+ if (cur_tag->id == Tag_HTML) {
+ hc->root_tag = cur_tag;
+ }
+ else {
+ /* Insert a fake html tag */
+ hc->all_tags.emplace_back(std::make_unique<html_tag>());
+ auto *top_tag = hc->all_tags.back().get();
+ top_tag->tag_start = 0;
+ top_tag->flags = CM_HEAD|FL_VIRTUAL;
+ top_tag->id = Tag_HTML;
+ top_tag->content_offset = 0;
+ top_tag->children.push_back(cur_tag);
+ cur_tag->parent = top_tag;
+ hc->root_tag = top_tag;
+ parent_tag = top_tag;
+ }
+ }
+ }
}
- /* XXX: uncomment when styles parsing is not so broken */
if (cur_tag->flags & FL_HREF && !in_head) {
auto maybe_url = html_process_url_tag(pool, cur_tag, hc);
std::sort(hc->all_tags.begin(), hc->all_tags.end(), [](const auto &pt1, const auto &pt2) -> auto {
return pt1->tag_start < pt2->tag_start;
});
- html_append_tags_content(pool, start, end - start, hc, exceptions, url_set);
+ html_append_tag_content(pool, start, end - start, hc, hc->root_tag,
+ exceptions, url_set);
}
/* Leftover */
{
const std::vector<std::pair<std::string, std::string>> cases{
- {"<div>foo</div><div>bar</div>", "foo\nbar\n"},
+ /* Complex html with bad tags */
+ {"<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <title>title</title>\n"
+ " <link rel=\"stylesheet\" href=\"style.css\">\n"
+ " <script src=\"script.js\"></script>\n"
+ " </head>\n"
+ " <body>\n"
+ " <!-- page content -->\n"
+ " Hello, world! <b>test</b>\n"
+ " <p>data<>\n"
+ " </P>\n"
+ " <b>stuff</p>?\n"
+ " </body>\n"
+ "</html>", "Hello, world! test\ndata<> \nstuff?"},
/* XML tags */
{"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
" <!DOCTYPE html\n"
{"test foo, bar", "test foo, bar"},
{"<p>text</p>", "text\n"},
{"olo<p>text</p>lolo", "olo\ntext\nlolo"},
+ {"<div>foo</div><div>bar</div>", "foo\nbar\n"},
{"<b>foo<i>bar</i>baz</b>", "foobarbaz"},
{"<b>foo<i>bar</b>baz</i>", "foobarbaz"},
{"foo<br>baz", "foo\nbaz"},
//{"<div>fi<span style=\"FONT-SIZE: 0px\">le </span>"
// "sh<span style=\"FONT-SIZE: 0px\">aring </div>foo</span>", "fish\nfoo"},
{"<p><!--comment-->test", "test"},
- /* Complex html with bad tags */
- {"<!DOCTYPE html>\n"
- "<html lang=\"en\">\n"
- " <head>\n"
- " <meta charset=\"utf-8\">\n"
- " <title>title</title>\n"
- " <link rel=\"stylesheet\" href=\"style.css\">\n"
- " <script src=\"script.js\"></script>\n"
- " </head>\n"
- " <body>\n"
- " <!-- page content -->\n"
- " Hello, world! <b>test</b>\n"
- " <p>data<>\n"
- " </P>\n"
- " <b>stuff</p>?\n"
- " </body>\n"
- "</html>", "Hello, world! test\ndata<> \nstuff?"},
+
};
rspamd_url_init(NULL);