Replacing only in the first match of <head> in the response

I’m using a a script to inject a <script> tag at the end of the <head> section of the response, and this works fine:

test_tag = b'<script src="test-fakeurl.js"></script></head>'
flow.response.content = flow.response.content.replace(b"</head>", test_tag)

I would like the option to do this replacement only the first time that the </head> match is found on the page, because otherwise the script will be injected into frames/iframes too, if they also have <head> sections. Initially, I tired using the optional count parameter for str.replace:

flow.response.content = flow.response.content.replace(b"</head>", test_tag, 1)

This does not work; all matches are still replaced. I then found closed ticket #1495 for this, where someone else confirms this doesn’t work. So I tried re.sub, which also has a count option:

flow.response.content = re.sub(b"</head>", test_tag, flow.response.content, count=1, flags=re.IGNORECASE)

Again, this doesn’t work. I’m wondering if each frame/iframe is actually being treated as a separate flow? If that’s the case, any ideas on how I could limit a replace operation to just the first <head> section?

Thanks!

I’m wondering if each frame/iframe is actually being treated as a separate flow?

Yes - this is how HTML works. I’m not sure if you can identify iframe requests by their HTTP headers, but you can identify it in the injected JavaScript: javascript - How to identify if a webpage is being loaded inside an iframe or directly into the browser window? - Stack Overflow

Thanks for confirming, and for the link!