LCOV - code coverage report
Current view: directory - toolkit/components/places - nsAnnoProtocolHandler.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 142 109 76.8 %
Date: 2012-06-02 Functions: 22 19 86.4 %

       1                 : //* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Annotation Service
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Google Inc.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2005
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Brett Wilson <brettw@gmail.com> (original author)
      24                 :  *   Shawn Wilsher <me@shawnwilsher.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : /**
      41                 :  * Implementation of moz-anno: URLs for accessing annotation values. This just
      42                 :  * reads binary data from the annotation service.
      43                 :  *
      44                 :  * There is a special case for favicons. Annotation URLs with the name "favicon"
      45                 :  * will be sent to the favicon service. If the favicon service doesn't have the
      46                 :  * data, a stream containing the default favicon will be returned.
      47                 :  */
      48                 : 
      49                 : #include "nsAnnoProtocolHandler.h"
      50                 : #include "nsFaviconService.h"
      51                 : #include "nsIChannel.h"
      52                 : #include "nsIInputStreamChannel.h"
      53                 : #include "nsILoadGroup.h"
      54                 : #include "nsIStandardURL.h"
      55                 : #include "nsIStringStream.h"
      56                 : #include "nsISupportsUtils.h"
      57                 : #include "nsIURI.h"
      58                 : #include "nsNetUtil.h"
      59                 : #include "nsServiceManagerUtils.h"
      60                 : #include "nsStringStream.h"
      61                 : #include "mozilla/storage.h"
      62                 : #include "nsIPipe.h"
      63                 : #include "Helpers.h"
      64                 : 
      65                 : using namespace mozilla;
      66                 : using namespace mozilla::places;
      67                 : 
      68                 : ////////////////////////////////////////////////////////////////////////////////
      69                 : //// Global Functions
      70                 : 
      71                 : /**
      72                 :  * Creates a channel to obtain the default favicon.
      73                 :  */
      74                 : static
      75                 : nsresult
      76               1 : GetDefaultIcon(nsIChannel **aChannel)
      77                 : {
      78               2 :   nsCOMPtr<nsIURI> defaultIconURI;
      79               1 :   nsresult rv = NS_NewURI(getter_AddRefs(defaultIconURI),
      80               2 :                           NS_LITERAL_CSTRING(FAVICON_DEFAULT_URL));
      81               1 :   NS_ENSURE_SUCCESS(rv, rv);
      82               1 :   return NS_NewChannel(aChannel, defaultIconURI);
      83                 : }
      84                 : 
      85                 : ////////////////////////////////////////////////////////////////////////////////
      86                 : //// faviconAsyncLoader
      87                 : 
      88                 : namespace {
      89                 : 
      90                 : /**
      91                 :  * An instance of this class is passed to the favicon service as the callback
      92                 :  * for getting favicon data from the database.  We'll get this data back in
      93                 :  * HandleResult, and on HandleCompletion, we'll close our output stream which
      94                 :  * will close the original channel for the favicon request.
      95                 :  *
      96                 :  * However, if an error occurs at any point, we do not set mReturnDefaultIcon to
      97                 :  * false, so we will open up another channel to get the default favicon, and
      98                 :  * pass that along to our output stream in HandleCompletion.  If anything
      99                 :  * happens at that point, the world must be against us, so we return nothing.
     100                 :  */
     101                 : class faviconAsyncLoader : public AsyncStatementCallback
     102                 :                          , public nsIRequestObserver
     103               8 : {
     104                 : public:
     105                 :   NS_DECL_ISUPPORTS_INHERITED
     106                 : 
     107               2 :   faviconAsyncLoader(nsIChannel *aChannel, nsIOutputStream *aOutputStream) :
     108                 :       mChannel(aChannel)
     109                 :     , mOutputStream(aOutputStream)
     110               2 :     , mReturnDefaultIcon(true)
     111                 :   {
     112               2 :     NS_ASSERTION(aChannel,
     113                 :                  "Not providing a channel will result in crashes!");
     114               2 :     NS_ASSERTION(aOutputStream,
     115                 :                  "Not providing an output stream will result in crashes!");
     116               2 :   }
     117                 : 
     118                 :   //////////////////////////////////////////////////////////////////////////////
     119                 :   //// mozIStorageStatementCallback
     120                 : 
     121               1 :   NS_IMETHOD HandleResult(mozIStorageResultSet *aResultSet)
     122                 :   {
     123                 :     // We will only get one row back in total, so we do not need to loop.
     124               2 :     nsCOMPtr<mozIStorageRow> row;
     125               1 :     nsresult rv = aResultSet->GetNextRow(getter_AddRefs(row));
     126               1 :     NS_ENSURE_SUCCESS(rv, rv);
     127                 : 
     128                 :     // We do not allow favicons without a MIME type, so we'll return the default
     129                 :     // icon.
     130               2 :     nsCAutoString mimeType;
     131               1 :     (void)row->GetUTF8String(1, mimeType);
     132               1 :     NS_ENSURE_FALSE(mimeType.IsEmpty(), NS_OK);
     133                 : 
     134                 :     // Set our mimeType now that we know it.
     135               1 :     rv = mChannel->SetContentType(mimeType);
     136               1 :     NS_ENSURE_SUCCESS(rv, rv);
     137                 : 
     138                 :     // Obtain the binary blob that contains our favicon data.
     139                 :     PRUint8 *favicon;
     140               1 :     PRUint32 size = 0;
     141               1 :     rv = row->GetBlob(0, &size, &favicon);
     142               1 :     NS_ENSURE_SUCCESS(rv, rv);
     143                 : 
     144               1 :     PRUint32 totalWritten = 0;
     145               1 :     do {
     146                 :       PRUint32 bytesWritten;
     147               1 :       rv = mOutputStream->Write(
     148                 :         &(reinterpret_cast<const char *>(favicon)[totalWritten]),
     149                 :         size - totalWritten,
     150                 :         &bytesWritten
     151               1 :       );
     152               1 :       if (NS_FAILED(rv) || !bytesWritten)
     153               0 :         break;
     154               1 :       totalWritten += bytesWritten;
     155                 :     } while (size != totalWritten);
     156               1 :     NS_ASSERTION(NS_FAILED(rv) || size == totalWritten,
     157                 :                  "Failed to write all of our data out to the stream!");
     158                 : 
     159                 :     // Free our favicon array.
     160               1 :     NS_Free(favicon);
     161                 : 
     162                 :     // Handle an error to write if it occurred, but only after we've freed our
     163                 :     // favicon.
     164               1 :     NS_ENSURE_SUCCESS(rv, rv);
     165                 : 
     166                 :     // At this point, we should have written out all of our data to our stream.
     167                 :     // HandleCompletion will close the output stream, so we are done here.
     168               1 :     mReturnDefaultIcon = false;
     169               1 :     return NS_OK;
     170                 :   }
     171                 : 
     172               2 :   NS_IMETHOD HandleCompletion(PRUint16 aReason)
     173                 :   {
     174               2 :     if (!mReturnDefaultIcon)
     175               1 :       return mOutputStream->Close();
     176                 : 
     177                 :     // We need to return our default icon, so we'll open up a new channel to get
     178                 :     // that data, and push it to our output stream.  If at any point we get an
     179                 :     // error, we can't do anything, so we'll just close our output stream.
     180               2 :     nsCOMPtr<nsIStreamListener> listener;
     181               1 :     nsresult rv = NS_NewSimpleStreamListener(getter_AddRefs(listener),
     182               1 :                                              mOutputStream, this);
     183               1 :     NS_ENSURE_SUCCESS(rv, mOutputStream->Close());
     184                 : 
     185               2 :     nsCOMPtr<nsIChannel> newChannel;
     186               1 :     rv = GetDefaultIcon(getter_AddRefs(newChannel));
     187               1 :     NS_ENSURE_SUCCESS(rv, mOutputStream->Close());
     188                 : 
     189               1 :     rv = newChannel->AsyncOpen(listener, nsnull);
     190               1 :     NS_ENSURE_SUCCESS(rv, mOutputStream->Close());
     191                 : 
     192               1 :     return NS_OK;
     193                 :   }
     194                 : 
     195                 :   //////////////////////////////////////////////////////////////////////////////
     196                 :   //// nsIRequestObserver
     197                 : 
     198               1 :   NS_IMETHOD OnStartRequest(nsIRequest *, nsISupports *)
     199                 :   {
     200               1 :     return NS_OK;
     201                 :   }
     202                 : 
     203               1 :   NS_IMETHOD OnStopRequest(nsIRequest *, nsISupports *, nsresult aStatusCode)
     204                 :   {
     205                 :     // We always need to close our output stream, regardless of the status code.
     206               1 :     (void)mOutputStream->Close();
     207                 : 
     208                 :     // But, we'll warn about it not being successful if it wasn't.
     209               1 :     NS_WARN_IF_FALSE(NS_SUCCEEDED(aStatusCode),
     210                 :                      "Got an error when trying to load our default favicon!");
     211                 : 
     212               1 :     return NS_OK;
     213                 :   }
     214                 : 
     215                 : private:
     216                 :   nsCOMPtr<nsIChannel> mChannel;
     217                 :   nsCOMPtr<nsIOutputStream> mOutputStream;
     218                 :   bool mReturnDefaultIcon;
     219                 : };
     220                 : 
     221              22 : NS_IMPL_ISUPPORTS_INHERITED1(
     222                 :   faviconAsyncLoader,
     223                 :   AsyncStatementCallback,
     224                 :   nsIRequestObserver
     225                 : )
     226                 : 
     227                 : } // anonymous namespace
     228                 : 
     229                 : ////////////////////////////////////////////////////////////////////////////////
     230                 : //// nsAnnoProtocolHandler
     231                 : 
     232             238 : NS_IMPL_ISUPPORTS1(nsAnnoProtocolHandler, nsIProtocolHandler)
     233                 : 
     234                 : // nsAnnoProtocolHandler::GetScheme
     235                 : 
     236                 : NS_IMETHODIMP
     237               0 : nsAnnoProtocolHandler::GetScheme(nsACString& aScheme)
     238                 : {
     239               0 :   aScheme.AssignLiteral("moz-anno");
     240               0 :   return NS_OK;
     241                 : }
     242                 : 
     243                 : 
     244                 : // nsAnnoProtocolHandler::GetDefaultPort
     245                 : //
     246                 : //    There is no default port for annotation URLs
     247                 : 
     248                 : NS_IMETHODIMP
     249               0 : nsAnnoProtocolHandler::GetDefaultPort(PRInt32 *aDefaultPort)
     250                 : {
     251               0 :   *aDefaultPort = -1;
     252               0 :   return NS_OK;
     253                 : }
     254                 : 
     255                 : 
     256                 : // nsAnnoProtocolHandler::GetProtocolFlags
     257                 : 
     258                 : NS_IMETHODIMP
     259               2 : nsAnnoProtocolHandler::GetProtocolFlags(PRUint32 *aProtocolFlags)
     260                 : {
     261                 :   *aProtocolFlags = (URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD |
     262               2 :                      URI_IS_LOCAL_RESOURCE);
     263               2 :   return NS_OK;
     264                 : }
     265                 : 
     266                 : 
     267                 : // nsAnnoProtocolHandler::NewURI
     268                 : 
     269                 : NS_IMETHODIMP
     270              24 : nsAnnoProtocolHandler::NewURI(const nsACString& aSpec,
     271                 :                               const char *aOriginCharset,
     272                 :                               nsIURI *aBaseURI, nsIURI **_retval)
     273                 : {
     274              48 :   nsCOMPtr <nsIURI> uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID);
     275              24 :   if (!uri)
     276               0 :     return NS_ERROR_OUT_OF_MEMORY;
     277              24 :   nsresult rv = uri->SetSpec(aSpec);
     278              24 :   NS_ENSURE_SUCCESS(rv, rv);
     279                 : 
     280              24 :   *_retval = nsnull;
     281              24 :   uri.swap(*_retval);
     282              24 :   return NS_OK;
     283                 : }
     284                 : 
     285                 : 
     286                 : // nsAnnoProtocolHandler::NewChannel
     287                 : //
     288                 : 
     289                 : NS_IMETHODIMP
     290               2 : nsAnnoProtocolHandler::NewChannel(nsIURI *aURI, nsIChannel **_retval)
     291                 : {
     292               2 :   NS_ENSURE_ARG_POINTER(aURI);
     293                 :   nsresult rv;
     294                 : 
     295               4 :   nsCAutoString path;
     296               2 :   rv = aURI->GetPath(path);
     297               2 :   NS_ENSURE_SUCCESS(rv, rv);
     298                 : 
     299                 :   nsCOMPtr<nsIAnnotationService> annotationService = do_GetService(
     300               4 :                               "@mozilla.org/browser/annotation-service;1", &rv);
     301               2 :   NS_ENSURE_SUCCESS(rv, rv);
     302                 : 
     303                 :   // annotation info
     304               4 :   nsCOMPtr<nsIURI> annoURI;
     305               4 :   nsCAutoString annoName;
     306               2 :   rv = ParseAnnoURI(aURI, getter_AddRefs(annoURI), annoName);
     307               2 :   NS_ENSURE_SUCCESS(rv, rv);
     308                 : 
     309                 :   // If this is a favicon annotation, we create a different channel that will
     310                 :   // ask the favicon service for information about the favicon.
     311               2 :   if (annoName.EqualsLiteral(FAVICON_ANNOTATION_NAME))
     312               2 :     return NewFaviconChannel(aURI, annoURI, _retval);
     313                 : 
     314                 :   // normal handling for annotations
     315                 :   PRUint8* data;
     316                 :   PRUint32 dataLen;
     317               0 :   nsCAutoString mimeType;
     318                 : 
     319                 :   // get the data from the annotation service and hand it off to the stream
     320               0 :   rv = annotationService->GetPageAnnotationBinary(annoURI, annoName, &data,
     321               0 :                                                   &dataLen, mimeType);
     322               0 :   NS_ENSURE_SUCCESS(rv, rv);
     323                 : 
     324                 :   // disallow annotations with no MIME types
     325               0 :   if (mimeType.IsEmpty()) {
     326               0 :     NS_Free(data);
     327               0 :     return NS_ERROR_NOT_AVAILABLE;
     328                 :   }
     329                 : 
     330                 :   nsCOMPtr<nsIStringInputStream> stream = do_CreateInstance(
     331               0 :                                           NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
     332               0 :   if (NS_FAILED(rv)) {
     333               0 :     NS_Free(data);
     334               0 :     return rv;
     335                 :   }
     336               0 :   rv = stream->AdoptData((char*)data, dataLen);
     337               0 :   if (NS_FAILED(rv)) {
     338               0 :     NS_Free(data);
     339               0 :     return rv;
     340                 :   }
     341                 : 
     342               0 :   nsCOMPtr<nsIChannel> channel;
     343               0 :   rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, stream, mimeType);
     344               0 :   NS_ENSURE_SUCCESS(rv, rv);
     345                 : 
     346               0 :   *_retval = channel;
     347               0 :   NS_ADDREF(*_retval);
     348               0 :   return NS_OK;
     349                 : }
     350                 : 
     351                 : 
     352                 : // nsAnnoProtocolHandler::AllowPort
     353                 : //
     354                 : //    Don't override any bans on bad ports.
     355                 : 
     356                 : NS_IMETHODIMP
     357               0 : nsAnnoProtocolHandler::AllowPort(PRInt32 port, const char *scheme,
     358                 :                                  bool *_retval)
     359                 : {
     360               0 :   *_retval = false;
     361               0 :   return NS_OK;
     362                 : }
     363                 : 
     364                 : 
     365                 : // nsAnnoProtocolHandler::ParseAnnoURI
     366                 : //
     367                 : //    Splits an annotation URL into its URI and name parts
     368                 : 
     369                 : nsresult
     370               2 : nsAnnoProtocolHandler::ParseAnnoURI(nsIURI* aURI,
     371                 :                                     nsIURI** aResultURI, nsCString& aName)
     372                 : {
     373                 :   nsresult rv;
     374               4 :   nsCAutoString path;
     375               2 :   rv = aURI->GetPath(path);
     376               2 :   NS_ENSURE_SUCCESS(rv, rv);
     377                 : 
     378               2 :   PRInt32 firstColon = path.FindChar(':');
     379               2 :   if (firstColon <= 0)
     380               0 :     return NS_ERROR_MALFORMED_URI;
     381                 : 
     382               2 :   rv = NS_NewURI(aResultURI, Substring(path, firstColon + 1));
     383               2 :   NS_ENSURE_SUCCESS(rv, rv);
     384                 : 
     385               2 :   aName = Substring(path, 0, firstColon);
     386               2 :   return NS_OK;
     387                 : }
     388                 : 
     389                 : nsresult
     390               2 : nsAnnoProtocolHandler::NewFaviconChannel(nsIURI *aURI, nsIURI *aAnnotationURI,
     391                 :                                          nsIChannel **_channel)
     392                 : {
     393                 :   // Create our pipe.  This will give us our input stream and output stream
     394                 :   // that will be written to when we get data from the database.
     395               4 :   nsCOMPtr<nsIInputStream> inputStream;
     396               4 :   nsCOMPtr<nsIOutputStream> outputStream;
     397               2 :   nsresult rv = NS_NewPipe(getter_AddRefs(inputStream),
     398               2 :                            getter_AddRefs(outputStream),
     399                 :                            MAX_FAVICON_SIZE, MAX_FAVICON_SIZE, true,
     400               2 :                            true);
     401               2 :   NS_ENSURE_SUCCESS(rv, GetDefaultIcon(_channel));
     402                 : 
     403                 :   // Create our channel.  We'll call SetContentType with the right type when
     404                 :   // we know what it actually is.
     405               4 :   nsCOMPtr<nsIChannel> channel;
     406               2 :   rv = NS_NewInputStreamChannel(getter_AddRefs(channel), aURI, inputStream,
     407               2 :                                 EmptyCString());
     408               2 :   NS_ENSURE_SUCCESS(rv, GetDefaultIcon(_channel));
     409                 : 
     410                 :   // Now we go ahead and get our data asynchronously for the favicon.
     411                 :   nsCOMPtr<mozIStorageStatementCallback> callback =
     412               6 :     new faviconAsyncLoader(channel, outputStream);
     413               2 :   NS_ENSURE_TRUE(callback, GetDefaultIcon(_channel));
     414               2 :   nsFaviconService* faviconService = nsFaviconService::GetFaviconService();
     415               2 :   NS_ENSURE_TRUE(faviconService, GetDefaultIcon(_channel));
     416                 : 
     417               2 :   rv = faviconService->GetFaviconDataAsync(aAnnotationURI, callback);
     418               2 :   NS_ENSURE_SUCCESS(rv, GetDefaultIcon(_channel));
     419                 : 
     420               2 :   channel.forget(_channel);
     421               2 :   return NS_OK;
     422                 : }

Generated by: LCOV version 1.7