LCOV - code coverage report
Current view: top level - dom/fetch - Response.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 10 148 6.8 %
Date: 2017-07-14 16:53:18 Functions: 6 18 33.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "Response.h"
       8             : 
       9             : #include "nsISupportsImpl.h"
      10             : #include "nsIURI.h"
      11             : #include "nsPIDOMWindow.h"
      12             : 
      13             : #include "mozilla/ErrorResult.h"
      14             : #include "mozilla/dom/FetchBinding.h"
      15             : #include "mozilla/dom/Headers.h"
      16             : #include "mozilla/dom/Promise.h"
      17             : #include "mozilla/dom/URL.h"
      18             : 
      19             : #include "nsDOMString.h"
      20             : 
      21             : #include "InternalResponse.h"
      22             : #include "WorkerPrivate.h"
      23             : 
      24             : namespace mozilla {
      25             : namespace dom {
      26             : 
      27           3 : NS_IMPL_CYCLE_COLLECTING_ADDREF(Response)
      28           2 : NS_IMPL_CYCLE_COLLECTING_RELEASE(Response)
      29           3 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Response, mOwner, mHeaders)
      30             : 
      31          10 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Response)
      32           1 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      33           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      34           0 : NS_INTERFACE_MAP_END
      35             : 
      36           1 : Response::Response(nsIGlobalObject* aGlobal, InternalResponse* aInternalResponse)
      37             :   : FetchBody<Response>(aGlobal)
      38           1 :   , mInternalResponse(aInternalResponse)
      39             : {
      40           1 :   MOZ_ASSERT(aInternalResponse->Headers()->Guard() == HeadersGuardEnum::Immutable ||
      41             :              aInternalResponse->Headers()->Guard() == HeadersGuardEnum::Response);
      42           1 :   SetMimeType();
      43           1 : }
      44             : 
      45           0 : Response::~Response()
      46             : {
      47           0 : }
      48             : 
      49             : /* static */ already_AddRefed<Response>
      50           0 : Response::Error(const GlobalObject& aGlobal)
      51             : {
      52           0 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
      53           0 :   RefPtr<InternalResponse> error = InternalResponse::NetworkError();
      54           0 :   RefPtr<Response> r = new Response(global, error);
      55           0 :   return r.forget();
      56             : }
      57             : 
      58             : /* static */ already_AddRefed<Response>
      59           0 : Response::Redirect(const GlobalObject& aGlobal, const nsAString& aUrl,
      60             :                    uint16_t aStatus, ErrorResult& aRv)
      61             : {
      62           0 :   nsAutoString parsedURL;
      63             : 
      64           0 :   if (NS_IsMainThread()) {
      65           0 :     nsCOMPtr<nsIURI> baseURI;
      66           0 :     nsIDocument* doc = GetEntryDocument();
      67           0 :     if (doc) {
      68           0 :       baseURI = doc->GetBaseURI();
      69             :     }
      70           0 :     nsCOMPtr<nsIURI> resolvedURI;
      71           0 :     aRv = NS_NewURI(getter_AddRefs(resolvedURI), aUrl, nullptr, baseURI);
      72           0 :     if (NS_WARN_IF(aRv.Failed())) {
      73           0 :       return nullptr;
      74             :     }
      75             : 
      76           0 :     nsAutoCString spec;
      77           0 :     aRv = resolvedURI->GetSpec(spec);
      78           0 :     if (NS_WARN_IF(aRv.Failed())) {
      79           0 :       return nullptr;
      80             :     }
      81             : 
      82           0 :     CopyUTF8toUTF16(spec, parsedURL);
      83             :   } else {
      84           0 :     workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
      85           0 :     MOZ_ASSERT(worker);
      86           0 :     worker->AssertIsOnWorkerThread();
      87             : 
      88           0 :     NS_ConvertUTF8toUTF16 baseURL(worker->GetLocationInfo().mHref);
      89           0 :     RefPtr<URL> url = URL::WorkerConstructor(aGlobal, aUrl, baseURL, aRv);
      90           0 :     if (aRv.Failed()) {
      91           0 :       return nullptr;
      92             :     }
      93             : 
      94           0 :     url->Stringify(parsedURL, aRv);
      95             :   }
      96             : 
      97           0 :   if (aRv.Failed()) {
      98           0 :     return nullptr;
      99             :   }
     100             : 
     101           0 :   if (aStatus != 301 && aStatus != 302 && aStatus != 303 && aStatus != 307 && aStatus != 308) {
     102           0 :     aRv.ThrowRangeError<MSG_INVALID_REDIRECT_STATUSCODE_ERROR>();
     103           0 :     return nullptr;
     104             :   }
     105             : 
     106           0 :   Optional<fetch::BodyInit> body;
     107           0 :   ResponseInit init;
     108           0 :   init.mStatus = aStatus;
     109           0 :   RefPtr<Response> r = Response::Constructor(aGlobal, body, init, aRv);
     110           0 :   if (NS_WARN_IF(aRv.Failed())) {
     111           0 :     return nullptr;
     112             :   }
     113             : 
     114           0 :   r->GetInternalHeaders()->Set(NS_LITERAL_CSTRING("Location"),
     115           0 :                                NS_ConvertUTF16toUTF8(parsedURL), aRv);
     116           0 :   if (NS_WARN_IF(aRv.Failed())) {
     117           0 :     return nullptr;
     118             :   }
     119           0 :   r->GetInternalHeaders()->SetGuard(HeadersGuardEnum::Immutable, aRv);
     120           0 :   MOZ_ASSERT(!aRv.Failed());
     121             : 
     122           0 :   return r.forget();
     123             : }
     124             : 
     125             : /*static*/ already_AddRefed<Response>
     126           0 : Response::Constructor(const GlobalObject& aGlobal,
     127             :                       const Optional<fetch::BodyInit>& aBody,
     128             :                       const ResponseInit& aInit, ErrorResult& aRv)
     129             : {
     130           0 :   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
     131             : 
     132           0 :   if (aInit.mStatus < 200 || aInit.mStatus > 599) {
     133           0 :     aRv.ThrowRangeError<MSG_INVALID_RESPONSE_STATUSCODE_ERROR>();
     134           0 :     return nullptr;
     135             :   }
     136             : 
     137             :   // Check if the status text contains illegal characters
     138           0 :   nsACString::const_iterator start, end;
     139           0 :   aInit.mStatusText.BeginReading(start);
     140           0 :   aInit.mStatusText.EndReading(end);
     141           0 :   if (FindCharInReadable('\r', start, end)) {
     142           0 :     aRv.ThrowTypeError<MSG_RESPONSE_INVALID_STATUSTEXT_ERROR>();
     143           0 :     return nullptr;
     144             :   }
     145             :   // Reset iterator since FindCharInReadable advances it.
     146           0 :   aInit.mStatusText.BeginReading(start);
     147           0 :   if (FindCharInReadable('\n', start, end)) {
     148           0 :     aRv.ThrowTypeError<MSG_RESPONSE_INVALID_STATUSTEXT_ERROR>();
     149           0 :     return nullptr;
     150             :   }
     151             : 
     152             :   RefPtr<InternalResponse> internalResponse =
     153           0 :     new InternalResponse(aInit.mStatus, aInit.mStatusText);
     154             : 
     155             :   // Grab a valid channel info from the global so this response is 'valid' for
     156             :   // interception.
     157           0 :   if (NS_IsMainThread()) {
     158           0 :     ChannelInfo info;
     159           0 :     nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
     160           0 :     if (window) {
     161           0 :       nsIDocument* doc = window->GetExtantDoc();
     162           0 :       MOZ_ASSERT(doc);
     163           0 :       info.InitFromDocument(doc);
     164             :     } else {
     165           0 :       info.InitFromChromeGlobal(global);
     166             :     }
     167           0 :     internalResponse->InitChannelInfo(info);
     168             :   } else {
     169           0 :     workers::WorkerPrivate* worker = workers::GetCurrentThreadWorkerPrivate();
     170           0 :     MOZ_ASSERT(worker);
     171           0 :     internalResponse->InitChannelInfo(worker->GetChannelInfo());
     172             :   }
     173             : 
     174           0 :   RefPtr<Response> r = new Response(global, internalResponse);
     175             : 
     176           0 :   if (aInit.mHeaders.WasPassed()) {
     177           0 :     internalResponse->Headers()->Clear();
     178             : 
     179             :     // Instead of using Fill, create an object to allow the constructor to
     180             :     // unwrap the HeadersInit.
     181             :     RefPtr<Headers> headers =
     182           0 :       Headers::Create(global, aInit.mHeaders.Value(), aRv);
     183           0 :     if (aRv.Failed()) {
     184           0 :       return nullptr;
     185             :     }
     186             : 
     187           0 :     internalResponse->Headers()->Fill(*headers->GetInternalHeaders(), aRv);
     188           0 :     if (NS_WARN_IF(aRv.Failed())) {
     189           0 :       return nullptr;
     190             :     }
     191             :   }
     192             : 
     193           0 :   if (aBody.WasPassed()) {
     194           0 :     if (aInit.mStatus == 204 || aInit.mStatus == 205 || aInit.mStatus == 304) {
     195           0 :       aRv.ThrowTypeError<MSG_RESPONSE_NULL_STATUS_WITH_BODY>();
     196           0 :       return nullptr;
     197             :     }
     198             : 
     199           0 :     nsCOMPtr<nsIInputStream> bodyStream;
     200           0 :     nsCString contentTypeWithCharset;
     201           0 :     uint64_t bodySize = 0;
     202           0 :     aRv = ExtractByteStreamFromBody(aBody.Value(),
     203           0 :                                     getter_AddRefs(bodyStream),
     204             :                                     contentTypeWithCharset,
     205           0 :                                     bodySize);
     206           0 :     if (NS_WARN_IF(aRv.Failed())) {
     207           0 :       return nullptr;
     208             :     }
     209           0 :     internalResponse->SetBody(bodyStream, bodySize);
     210             : 
     211           0 :     if (!contentTypeWithCharset.IsVoid() &&
     212           0 :         !internalResponse->Headers()->Has(NS_LITERAL_CSTRING("Content-Type"),
     213           0 :                                           aRv)) {
     214             :       // Ignore Append() failing here.
     215           0 :       ErrorResult error;
     216           0 :       internalResponse->Headers()->Append(NS_LITERAL_CSTRING("Content-Type"),
     217           0 :                                           contentTypeWithCharset, error);
     218           0 :       error.SuppressException();
     219             :     }
     220             : 
     221           0 :     if (aRv.Failed()) {
     222           0 :       return nullptr;
     223             :     }
     224             :   }
     225             : 
     226           0 :   r->SetMimeType();
     227           0 :   return r.forget();
     228             : }
     229             : 
     230             : already_AddRefed<Response>
     231           0 : Response::Clone(ErrorResult& aRv) const
     232             : {
     233           0 :   if (BodyUsed()) {
     234           0 :     aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
     235           0 :     return nullptr;
     236             :   }
     237             : 
     238           0 :   RefPtr<InternalResponse> ir = mInternalResponse->Clone();
     239           0 :   RefPtr<Response> response = new Response(mOwner, ir);
     240           0 :   return response.forget();
     241             : }
     242             : 
     243             : already_AddRefed<Response>
     244           0 : Response::CloneUnfiltered(ErrorResult& aRv) const
     245             : {
     246           0 :   if (BodyUsed()) {
     247           0 :     aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
     248           0 :     return nullptr;
     249             :   }
     250             : 
     251           0 :   RefPtr<InternalResponse> clone = mInternalResponse->Clone();
     252           0 :   RefPtr<InternalResponse> ir = clone->Unfiltered();
     253           0 :   RefPtr<Response> ref = new Response(mOwner, ir);
     254           0 :   return ref.forget();
     255             : }
     256             : 
     257             : void
     258           0 : Response::SetBody(nsIInputStream* aBody, int64_t aBodySize)
     259             : {
     260           0 :   MOZ_ASSERT(!BodyUsed());
     261           0 :   mInternalResponse->SetBody(aBody, aBodySize);
     262           0 : }
     263             : 
     264             : already_AddRefed<InternalResponse>
     265           0 : Response::GetInternalResponse() const
     266             : {
     267           0 :   RefPtr<InternalResponse> ref = mInternalResponse;
     268           0 :   return ref.forget();
     269             : }
     270             : 
     271             : Headers*
     272           0 : Response::Headers_()
     273             : {
     274           0 :   if (!mHeaders) {
     275           0 :     mHeaders = new Headers(mOwner, mInternalResponse->Headers());
     276             :   }
     277             : 
     278           0 :   return mHeaders;
     279             : }
     280             : 
     281             : } // namespace dom
     282             : } // namespace mozilla

Generated by: LCOV version 1.13