Skip to content

Rewrite Icon fetching#3023

Merged
justindbaur merged 35 commits into
masterfrom
platform/pm-2122/use-validated-ip-in-icon-retrieval
Aug 8, 2023
Merged

Rewrite Icon fetching#3023
justindbaur merged 35 commits into
masterfrom
platform/pm-2122/use-validated-ip-in-icon-retrieval

Conversation

@MGibson1

Copy link
Copy Markdown
Member

Type of change

- [ ] Bug fix
- [ ] New feature development
- [ ] Tech debt (refactoring, code cleanup, dependency upgrades, etc)
- [ ] Build/deploy pipeline (DevOps)
- [ ] Other

Objective

Rewrites icon fetching to be more object oriented.

Code changes

  • DomainIcons: Object controlling all icons retrieved for a given domain. Handles creation of potential uri locations for a given domain
  • IconHttpRequest: Simplified HttpRequest class for Icon fetching. Handles limited redirect following and ensures use of validated IP addresses only.
  • IconHttpResponse: HttpResponseMessage wrapper. Parses responses for Icon links, and retrieves them, collating into a list of Icons from a response.
  • IconLink: Known link to an Icon. Retrives content and parses it into an Icon
  • IconUri: Handles Icon validation and swap to IP
  • Startup: Swap over to using HttpClientFactory with the same settings as the old static HttpClient
  • IPAddressExtension & UriExtension: Useful validation and manipulation extensions
  • Tests: Not much testing here, but I did update to match the new DI requirements and added a test that still uses /favicon.ico as the resolved icon location.

Before you submit

  • Please check for formatting errors (dotnet format --verify-no-changes) (required)
  • If making database changes - make sure you also update Entity Framework queries and/or migrations
  • Please add unit tests where it makes sense to do so (encouraged but not required)
  • If this change requires a documentation update - notify the documentation team
  • If this change has particular deployment requirements - notify the DevOps team

@bw-ephemeral-env-bot

Copy link
Copy Markdown

Ephemeral Environment

Server Branch/Tag Web Branch/Tag Status
platform-pm-2122-use-validated-ip-in-icon-retrieval latest -
- - -

Instructions

Details

Creating a new environment

  1. Edit this comment and change the server and web branches/tags to your desired environment.
  2. Add the ee label to this PR.
  3. The bot will begin to create a new environment.

Updating an environment

  1. As you push new commits, the bot will automatically update your environment.

Deletion of an environment

NOTE: Environments will be automatically deleted on merge/close of a PR.

  1. Remove the ee label from the PR.
  2. The bot will destroy the environment.

Additional information can be found here.

@MGibson1 MGibson1 force-pushed the platform/pm-2122/use-validated-ip-in-icon-retrieval branch from ef80a5f to 817c3d9 Compare June 16, 2023 12:29

@justindbaur justindbaur left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on passing through the CancellationToken from HttpContext.RequestAborted to all the async calls, this way if the connection gets closed we can stop doing all this work.

With something that has no database side effects I'd normally really want to do that but I can also see an argument against it because we can let the request continue and let it make it into our cache so that we can return the cached version the next time.

Comment thread src/Icons/Models/IconHttpRequest.cs Outdated
Comment thread src/Icons/Models/DomainIcons.cs Outdated
Comment thread src/Icons/Models/IconHttpRequest.cs Outdated
Comment thread src/Icons/Models/IconHttpResponse.cs Outdated
Comment thread src/Icons/Models/IconHttpRequest.cs Outdated
Comment thread src/Icons/Models/IconHttpResponse.cs Outdated
Comment thread src/Icons/Util/UriExtension.cs Outdated
Comment thread test/Icons.Test/Services/ServiceTestBase.cs Outdated
Comment thread src/Icons/Models/IconLink.cs
Comment thread src/Icons/Models/DomainIcons.cs

@withinfocus withinfocus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestions from Justin. I see a couple ⛏️ s beyond that but will skip calling them out until this settles.

Comment thread src/Icons/Models/DomainIcons.cs Outdated
Comment thread src/Icons/Models/IconHttpResponse.cs Outdated
_httpClientFactory = httpClientFactory;
}

public async Task<IEnumerable<Icon>> RetrieveIconsAsync(Uri requestUri, string domain)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 Does it make sense to just have this return one? Is there a use case I'm not seeing for providing all of what's found?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm this is pretty interesting. We used to prioritize icon display after pulling, but now that prioritization occurs prior to navigating to a link. That does mean that we could pull only the highest priority and cut down on network requests.

However, if the first link fails, we'd have to go on down the line iteratively. Currently, we just fire off all 10 requests simultaneously and wait for them all to get back to us. Effectively we're discussing changing this from an eager load to a lazy one.

I don't have the data to say which would be better, presumably most links work, but those that don't would suffer in load times.

@bitwarden-bot

bitwarden-bot commented Jul 6, 2023

Copy link
Copy Markdown
Collaborator

Logo
Checkmarx One – Scan Summary & Details8639c76c-8843-45f7-8cb4-fb88ca1ea26c

No New Or Fixed Issues Found

@MGibson1

Copy link
Copy Markdown
Member Author

Looking in to test failures. I swear they weren't happening locally a half hour ago... 😵

MGibson1 added 2 commits July 11, 2023 12:23
Content was being disposed when HttResponseMessage was being disposed.
This avoids losing our reference to our content and allows multiple
usages of the same `MockedHttpMessageResponse`
Extension is shared by testing and allows access to services from
our service tests
@MGibson1 MGibson1 marked this pull request as ready for review July 11, 2023 17:06

@withinfocus withinfocus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ton of changes here, but I think it's making sense to me and has a lot of test coverage. Few questions.

Comment thread test/Common/MockedHttpClient/HttpRequestMatcher.cs Outdated
Comment thread test/Common/MockedHttpClient/MockedHttpMessageHandler.cs Outdated
Comment thread test/Common/MockedHttpClient/MockedHttpResponse.cs Outdated
public class IconFetchingServiceTests : ServiceTestBase<IconFetchingService>
{
[Theory]
[InlineData("www.twitter.com")] // https site

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ Anything special with how this test was handled? Seems the same as the line below.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From when I stepped through the retrieval it's the same as google, we have just been getting reports that twitter in particular is having problems.

Because this work is so pervasive I have no clue if this test passing represents a functionality change or not, but I wanted this as a canary. If it proves to be flaky on twitter's end I want to remove.

@MGibson1 MGibson1 requested a review from withinfocus July 11, 2023 21:41
justindbaur
justindbaur previously approved these changes Jul 17, 2023

@justindbaur justindbaur left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great stuff!

Comment thread src/Icons/Models/IconLink.cs Outdated
justindbaur
justindbaur previously approved these changes Jul 17, 2023
@justindbaur justindbaur disabled auto-merge July 18, 2023 14:22
@justindbaur justindbaur enabled auto-merge (squash) July 18, 2023 14:22
private const string _jpegMediaType = "image/jpeg";
private static readonly byte[] _jpegHeader = new byte[] { 255, 216, 255 };

private const string _svgXmlMediaType = "image/svg+xml";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 Does there need to be a code expansion below to check the header? I see this done for the other types.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to, those are only for formats that we try to infer if we don't get a Media-Type header back or we don't support the media type we got back. I also don't think there are generally "marker" bytes for svg.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throwing in an additional test theory with a site that uses an SVG icon would be a nice and quick addition.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there doesn't need to be mime type detection on the file level. That's just a fallback if the mimetype doesn't exist.

I don't believe svg+xml has a mime type file header (I couldn't find one) so it's not added.

justindbaur
justindbaur previously approved these changes Aug 7, 2023
@MGibson1 MGibson1 removed the needs-qa label Aug 8, 2023
@justindbaur justindbaur merged commit 4377c7a into master Aug 8, 2023
@justindbaur justindbaur deleted the platform/pm-2122/use-validated-ip-in-icon-retrieval branch August 8, 2023 19:29
MGibson1 added a commit that referenced this pull request Aug 15, 2023
* Rewrite Icon fetching

* Move validation to IconUri, Uri, or UriBuilder

* `dotnet format` 🤖

* PR suggestions

* Add not null compiler hint

* Add twitter to test case

* Move Uri manipulation to UriService

* Implement MockedHttpClient

Presents better, fluent handling of message matching and response
building.

* Add redirect handling tests

* Add testing to models

* More aggressively dispose content in icon link

* Format 🤖

* Update icon lockfile

* Convert to cloned stream for HttpResponseBuilder

Content was being disposed when HttResponseMessage was being disposed.
This avoids losing our reference to our content and allows multiple
usages of the same `MockedHttpMessageResponse`

* Move services to extension

Extension is shared by testing and allows access to services from
our service tests

* Remove unused `using`

* Prefer awaiting asyncs for better exception handling

* `dotnet format` 🤖

* Await async

* Update tests to use test TLD and ip ranges

* Remove unused interfaces

* Make assignments static when possible

* Prefer invariant comparer to downcasing

* Prefer injecting interface services to implementations

* Prefer comparer set in HashSet initialization

* Allow SVG icons

* Filter out icons with unknown formats

* Seek to beginning of MemoryStream after writing it

* More appropriate to not return icon if it's invalid

* Add svg icon test

(cherry picked from commit 4377c7a)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants