LCOV - code coverage report
Current view: top level - toolkit/components/places - nsAnnoProtocolHandler.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 133 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 21 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : /**
       7             :  * Implementation of moz-anno: URLs for accessing favicons.  The urls are sent
       8             :  * to the favicon service.  If the favicon service doesn't have the
       9             :  * data, a stream containing the default favicon will be returned.
      10             :  *
      11             :  * The reference to annotations ("moz-anno") is a leftover from previous
      12             :  * iterations of this component. As of now the moz-anno protocol is independent
      13             :  * of annotations.
      14             :  */
      15             : 
      16             : #include "nsAnnoProtocolHandler.h"
      17             : #include "nsFaviconService.h"
      18             : #include "nsIChannel.h"
      19             : #include "nsIInputStreamChannel.h"
      20             : #include "nsILoadGroup.h"
      21             : #include "nsIStandardURL.h"
      22             : #include "nsIStringStream.h"
      23             : #include "nsIInputStream.h"
      24             : #include "nsISupportsUtils.h"
      25             : #include "nsIURI.h"
      26             : #include "nsNetUtil.h"
      27             : #include "nsIOutputStream.h"
      28             : #include "nsInputStreamPump.h"
      29             : #include "nsContentUtils.h"
      30             : #include "nsServiceManagerUtils.h"
      31             : #include "nsStringStream.h"
      32             : #include "SimpleChannel.h"
      33             : #include "mozilla/ScopeExit.h"
      34             : #include "mozilla/storage.h"
      35             : #include "Helpers.h"
      36             : #include "FaviconHelpers.h"
      37             : 
      38             : using namespace mozilla;
      39             : using namespace mozilla::places;
      40             : 
      41             : ////////////////////////////////////////////////////////////////////////////////
      42             : //// Global Functions
      43             : 
      44             : /**
      45             :  * Creates a channel to obtain the default favicon.
      46             :  */
      47             : static
      48             : nsresult
      49           0 : GetDefaultIcon(nsIChannel *aOriginalChannel, nsIChannel **aChannel)
      50             : {
      51           0 :   nsCOMPtr<nsIURI> defaultIconURI;
      52           0 :   nsresult rv = NS_NewURI(getter_AddRefs(defaultIconURI),
      53           0 :                           NS_LITERAL_CSTRING(FAVICON_DEFAULT_URL));
      54           0 :   NS_ENSURE_SUCCESS(rv, rv);
      55           0 :   nsCOMPtr<nsILoadInfo> loadInfo = aOriginalChannel->GetLoadInfo();
      56           0 :   rv = NS_NewChannelInternal(aChannel, defaultIconURI, loadInfo);
      57           0 :   NS_ENSURE_SUCCESS(rv, rv);
      58           0 :   Unused << (*aChannel)->SetContentType(NS_LITERAL_CSTRING(FAVICON_DEFAULT_MIMETYPE));
      59           0 :   Unused << aOriginalChannel->SetContentType(NS_LITERAL_CSTRING(FAVICON_DEFAULT_MIMETYPE));
      60           0 :   return NS_OK;
      61             : }
      62             : 
      63             : ////////////////////////////////////////////////////////////////////////////////
      64             : //// faviconAsyncLoader
      65             : 
      66             : namespace {
      67             : 
      68             : /**
      69             :  * An instance of this class is passed to the favicon service as the callback
      70             :  * for getting favicon data from the database.  We'll get this data back in
      71             :  * HandleResult, and on HandleCompletion, we'll close our output stream which
      72             :  * will close the original channel for the favicon request.
      73             :  *
      74             :  * However, if an error occurs at any point and we don't have mData, we will
      75             :  * just fallback to the default favicon.  If anything happens at that point, the
      76             :  * world must be against us, so we can do nothing.
      77             :  */
      78             : class faviconAsyncLoader : public AsyncStatementCallback
      79             : {
      80             : public:
      81           0 :   faviconAsyncLoader(nsIChannel *aChannel, nsIStreamListener *aListener,
      82             :                      uint16_t aPreferredSize)
      83           0 :     : mChannel(aChannel)
      84             :     , mListener(aListener)
      85           0 :     , mPreferredSize(aPreferredSize)
      86             :   {
      87           0 :     MOZ_ASSERT(aChannel, "Not providing a channel will result in crashes!");
      88           0 :     MOZ_ASSERT(aListener, "Not providing a stream listener will result in crashes!");
      89           0 :     MOZ_ASSERT(aChannel, "Not providing a channel!");
      90           0 :   }
      91             : 
      92             :   //////////////////////////////////////////////////////////////////////////////
      93             :   //// mozIStorageStatementCallback
      94             : 
      95           0 :   NS_IMETHOD HandleResult(mozIStorageResultSet *aResultSet) override
      96             :   {
      97           0 :     nsCOMPtr<mozIStorageRow> row;
      98           0 :     while (NS_SUCCEEDED(aResultSet->GetNextRow(getter_AddRefs(row))) && row) {
      99             :       int32_t width;
     100           0 :       nsresult rv = row->GetInt32(1, &width);
     101           0 :       NS_ENSURE_SUCCESS(rv, rv);
     102             : 
     103             :       // Check if we already found an image >= than the preferred size,
     104             :       // otherwise keep examining the next results.
     105           0 :       if (width < mPreferredSize && !mData.IsEmpty()) {
     106           0 :         return NS_OK;
     107             :       }
     108             : 
     109             :       // Eventually override the default mimeType for svg.
     110           0 :       if (width == UINT16_MAX) {
     111           0 :         rv = mChannel->SetContentType(NS_LITERAL_CSTRING(SVG_MIME_TYPE));
     112             :       } else {
     113           0 :         rv = mChannel->SetContentType(NS_LITERAL_CSTRING(PNG_MIME_TYPE));
     114             :       }
     115           0 :       NS_ENSURE_SUCCESS(rv, rv);
     116             : 
     117             :       // Obtain the binary blob that contains our favicon data.
     118             :       uint8_t *data;
     119             :       uint32_t dataLen;
     120           0 :       rv = row->GetBlob(0, &dataLen, &data);
     121           0 :       NS_ENSURE_SUCCESS(rv, rv);
     122           0 :       mData.Adopt(TO_CHARBUFFER(data), dataLen);
     123             :     }
     124             : 
     125           0 :     return NS_OK;
     126             :   }
     127             : 
     128           0 :   NS_IMETHOD HandleCompletion(uint16_t aReason) override
     129             :   {
     130           0 :     MOZ_DIAGNOSTIC_ASSERT(mListener);
     131           0 :     NS_ENSURE_TRUE(mListener, NS_ERROR_UNEXPECTED);
     132             : 
     133             :     nsresult rv;
     134             :     // Ensure we'll break possible cycles with the listener.
     135           0 :     auto cleanup = MakeScopeExit([&] () {
     136           0 :       mListener = nullptr;
     137           0 :     });
     138             : 
     139           0 :     nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
     140             :     nsCOMPtr<nsIEventTarget> target =
     141           0 :       nsContentUtils::GetEventTargetByLoadInfo(loadInfo, TaskCategory::Other);
     142           0 :     if (!mData.IsEmpty()) {
     143           0 :       nsCOMPtr<nsIInputStream> stream;
     144           0 :       rv = NS_NewCStringInputStream(getter_AddRefs(stream), mData);
     145           0 :       MOZ_ASSERT(NS_SUCCEEDED(rv));
     146           0 :       if (NS_SUCCEEDED(rv)) {
     147           0 :         RefPtr<nsInputStreamPump> pump;
     148           0 :         rv = nsInputStreamPump::Create(getter_AddRefs(pump), stream, -1, -1, 0, 0,
     149           0 :                                        true, target);
     150           0 :         MOZ_ASSERT(NS_SUCCEEDED(rv));
     151           0 :         if (NS_SUCCEEDED(rv)) {
     152           0 :           return pump->AsyncRead(mListener, nullptr);
     153             :         }
     154             :       }
     155             :     }
     156             : 
     157             :     // Fallback to the default favicon.
     158             :     // we should pass the loadInfo of the original channel along
     159             :     // to the new channel. Note that mChannel can not be null,
     160             :     // constructor checks that.
     161           0 :     nsCOMPtr<nsIChannel> newChannel;
     162           0 :     rv = GetDefaultIcon(mChannel, getter_AddRefs(newChannel));
     163           0 :     if (NS_FAILED(rv)) {
     164           0 :       mListener->OnStartRequest(mChannel, nullptr);
     165           0 :       mListener->OnStopRequest(mChannel, nullptr, rv);
     166           0 :       return rv;
     167             :     }
     168           0 :     return newChannel->AsyncOpen2(mListener);
     169             :   }
     170             : 
     171             : protected:
     172           0 :   virtual ~faviconAsyncLoader() {}
     173             : 
     174             : private:
     175             :   nsCOMPtr<nsIChannel> mChannel;
     176             :   nsCOMPtr<nsIStreamListener> mListener;
     177             :   nsCString mData;
     178             :   uint16_t mPreferredSize;
     179             : };
     180             : 
     181             : } // namespace
     182             : 
     183             : ////////////////////////////////////////////////////////////////////////////////
     184             : //// nsAnnoProtocolHandler
     185             : 
     186           0 : NS_IMPL_ISUPPORTS(nsAnnoProtocolHandler, nsIProtocolHandler)
     187             : 
     188             : // nsAnnoProtocolHandler::GetScheme
     189             : 
     190             : NS_IMETHODIMP
     191           0 : nsAnnoProtocolHandler::GetScheme(nsACString& aScheme)
     192             : {
     193           0 :   aScheme.AssignLiteral("moz-anno");
     194           0 :   return NS_OK;
     195             : }
     196             : 
     197             : 
     198             : // nsAnnoProtocolHandler::GetDefaultPort
     199             : //
     200             : //    There is no default port for annotation URLs
     201             : 
     202             : NS_IMETHODIMP
     203           0 : nsAnnoProtocolHandler::GetDefaultPort(int32_t *aDefaultPort)
     204             : {
     205           0 :   *aDefaultPort = -1;
     206           0 :   return NS_OK;
     207             : }
     208             : 
     209             : 
     210             : // nsAnnoProtocolHandler::GetProtocolFlags
     211             : 
     212             : NS_IMETHODIMP
     213           0 : nsAnnoProtocolHandler::GetProtocolFlags(uint32_t *aProtocolFlags)
     214             : {
     215           0 :   *aProtocolFlags = (URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD |
     216             :                      URI_IS_LOCAL_RESOURCE);
     217           0 :   return NS_OK;
     218             : }
     219             : 
     220             : 
     221             : // nsAnnoProtocolHandler::NewURI
     222             : 
     223             : NS_IMETHODIMP
     224           0 : nsAnnoProtocolHandler::NewURI(const nsACString& aSpec,
     225             :                               const char *aOriginCharset,
     226             :                               nsIURI *aBaseURI, nsIURI **_retval)
     227             : {
     228           0 :   nsCOMPtr <nsIURI> uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID);
     229           0 :   if (!uri)
     230           0 :     return NS_ERROR_OUT_OF_MEMORY;
     231           0 :   nsresult rv = uri->SetSpec(aSpec);
     232           0 :   NS_ENSURE_SUCCESS(rv, rv);
     233             : 
     234           0 :   *_retval = nullptr;
     235           0 :   uri.swap(*_retval);
     236           0 :   return NS_OK;
     237             : }
     238             : 
     239             : 
     240             : // nsAnnoProtocolHandler::NewChannel
     241             : //
     242             : 
     243             : NS_IMETHODIMP
     244           0 : nsAnnoProtocolHandler::NewChannel2(nsIURI* aURI,
     245             :                                    nsILoadInfo* aLoadInfo,
     246             :                                    nsIChannel** _retval)
     247             : {
     248           0 :   NS_ENSURE_ARG_POINTER(aURI);
     249             : 
     250             :   // annotation info
     251           0 :   nsCOMPtr<nsIURI> annoURI;
     252           0 :   nsAutoCString annoName;
     253           0 :   nsresult rv = ParseAnnoURI(aURI, getter_AddRefs(annoURI), annoName);
     254           0 :   NS_ENSURE_SUCCESS(rv, rv);
     255             : 
     256             :   // Only favicon annotation are supported.
     257           0 :   if (!annoName.EqualsLiteral(FAVICON_ANNOTATION_NAME))
     258           0 :     return NS_ERROR_INVALID_ARG;
     259             : 
     260           0 :   return NewFaviconChannel(aURI, annoURI, aLoadInfo, _retval);
     261             : }
     262             : 
     263             : NS_IMETHODIMP
     264           0 : nsAnnoProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
     265             : {
     266           0 :   return NewChannel2(aURI, nullptr, _retval);
     267             : }
     268             : 
     269             : 
     270             : // nsAnnoProtocolHandler::AllowPort
     271             : //
     272             : //    Don't override any bans on bad ports.
     273             : 
     274             : NS_IMETHODIMP
     275           0 : nsAnnoProtocolHandler::AllowPort(int32_t port, const char *scheme,
     276             :                                  bool *_retval)
     277             : {
     278           0 :   *_retval = false;
     279           0 :   return NS_OK;
     280             : }
     281             : 
     282             : 
     283             : // nsAnnoProtocolHandler::ParseAnnoURI
     284             : //
     285             : //    Splits an annotation URL into its URI and name parts
     286             : 
     287             : nsresult
     288           0 : nsAnnoProtocolHandler::ParseAnnoURI(nsIURI* aURI,
     289             :                                     nsIURI** aResultURI, nsCString& aName)
     290             : {
     291             :   nsresult rv;
     292           0 :   nsAutoCString path;
     293           0 :   rv = aURI->GetPath(path);
     294           0 :   NS_ENSURE_SUCCESS(rv, rv);
     295             : 
     296           0 :   int32_t firstColon = path.FindChar(':');
     297           0 :   if (firstColon <= 0)
     298           0 :     return NS_ERROR_MALFORMED_URI;
     299             : 
     300           0 :   rv = NS_NewURI(aResultURI, Substring(path, firstColon + 1));
     301           0 :   NS_ENSURE_SUCCESS(rv, rv);
     302             : 
     303           0 :   aName = Substring(path, 0, firstColon);
     304           0 :   return NS_OK;
     305             : }
     306             : 
     307             : nsresult
     308           0 : nsAnnoProtocolHandler::NewFaviconChannel(nsIURI *aURI, nsIURI *aAnnotationURI,
     309             :                                          nsILoadInfo* aLoadInfo, nsIChannel **_channel)
     310             : {
     311             :   // Create our channel.  We'll call SetContentType with the right type when
     312             :   // we know what it actually is.
     313           0 :   nsCOMPtr<nsIChannel> channel = NS_NewSimpleChannel(
     314             :     aURI, aLoadInfo, aAnnotationURI,
     315           0 :     [] (nsIStreamListener* listener, nsIChannel* channel, nsIURI* annotationURI) {
     316           0 :       auto fallback = [&] () -> RequestOrReason {
     317           0 :         nsCOMPtr<nsIChannel> chan;
     318           0 :         nsresult rv = GetDefaultIcon(channel, getter_AddRefs(chan));
     319           0 :         NS_ENSURE_SUCCESS(rv, Err(rv));
     320             : 
     321           0 :         rv = chan->AsyncOpen2(listener);
     322           0 :         NS_ENSURE_SUCCESS(rv, Err(rv));
     323             : 
     324           0 :         return RequestOrReason(chan.forget());
     325           0 :       };
     326             : 
     327             :       // Now we go ahead and get our data asynchronously for the favicon.
     328             :       // Ignore the ref part of the URI before querying the database because
     329             :       // we may have added a size fragment for rendering purposes.
     330           0 :       nsFaviconService* faviconService = nsFaviconService::GetFaviconService();
     331           0 :       nsAutoCString faviconSpec;
     332           0 :       nsresult rv = annotationURI->GetSpecIgnoringRef(faviconSpec);
     333             :       // Any failures fallback to the default icon channel.
     334           0 :       if (NS_FAILED(rv) || !faviconService)
     335           0 :         return fallback();
     336             : 
     337           0 :       uint16_t preferredSize = UINT16_MAX;
     338           0 :       MOZ_ALWAYS_SUCCEEDS(faviconService->PreferredSizeFromURI(annotationURI, &preferredSize));
     339             :       nsCOMPtr<mozIStorageStatementCallback> callback =
     340           0 :         new faviconAsyncLoader(channel, listener, preferredSize);
     341           0 :       if (!callback)
     342           0 :         return fallback();
     343             : 
     344           0 :       rv = faviconService->GetFaviconDataAsync(faviconSpec, callback);
     345           0 :       if (NS_FAILED(rv))
     346           0 :         return fallback();
     347             : 
     348           0 :       return RequestOrReason(nullptr);
     349           0 :     });
     350           0 :   NS_ENSURE_TRUE(channel, NS_ERROR_OUT_OF_MEMORY);
     351             : 
     352           0 :   channel.forget(_channel);
     353           0 :   return NS_OK;
     354             : }

Generated by: LCOV version 1.13