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 "InternalResponse.h"
8 
9 #include "mozilla/Assertions.h"
10 #include "mozilla/dom/InternalHeaders.h"
11 #include "mozilla/dom/cache/CacheTypes.h"
12 #include "mozilla/ipc/PBackgroundSharedTypes.h"
13 #include "mozilla/ipc/IPCStreamUtils.h"
14 #include "nsIURI.h"
15 #include "nsStreamUtils.h"
16 
17 namespace mozilla {
18 namespace dom {
19 
InternalResponse(uint16_t aStatus,const nsACString & aStatusText)20 InternalResponse::InternalResponse(uint16_t aStatus, const nsACString& aStatusText)
21   : mType(ResponseType::Default)
22   , mStatus(aStatus)
23   , mStatusText(aStatusText)
24   , mHeaders(new InternalHeaders(HeadersGuardEnum::Response))
25   , mBodySize(UNKNOWN_BODY_SIZE)
26 {
27 }
28 
29 already_AddRefed<InternalResponse>
FromIPC(const IPCInternalResponse & aIPCResponse)30 InternalResponse::FromIPC(const IPCInternalResponse& aIPCResponse)
31 {
32   if (aIPCResponse.type() == ResponseType::Error) {
33     return InternalResponse::NetworkError();
34   }
35 
36   RefPtr<InternalResponse> response =
37     new InternalResponse(aIPCResponse.status(),
38                          aIPCResponse.statusText());
39 
40   response->SetURLList(aIPCResponse.urlList());
41 
42   response->mHeaders = new InternalHeaders(aIPCResponse.headers(),
43                                            aIPCResponse.headersGuard());
44 
45   response->InitChannelInfo(aIPCResponse.channelInfo());
46   if (aIPCResponse.principalInfo().type() == mozilla::ipc::OptionalPrincipalInfo::TPrincipalInfo) {
47     UniquePtr<mozilla::ipc::PrincipalInfo> info(new mozilla::ipc::PrincipalInfo(aIPCResponse.principalInfo().get_PrincipalInfo()));
48     response->SetPrincipalInfo(Move(info));
49   }
50 
51   nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aIPCResponse.body());
52   response->SetBody(stream, aIPCResponse.bodySize());
53 
54   switch (aIPCResponse.type())
55   {
56     case ResponseType::Basic:
57       response = response->BasicResponse();
58       break;
59     case ResponseType::Cors:
60       response = response->CORSResponse();
61       break;
62     case ResponseType::Default:
63       break;
64     case ResponseType::Opaque:
65       response = response->OpaqueResponse();
66       break;
67     case ResponseType::Opaqueredirect:
68       response = response->OpaqueRedirectResponse();
69       break;
70     default:
71       MOZ_CRASH("Unexpected ResponseType!");
72   }
73   MOZ_ASSERT(response);
74 
75   return response.forget();
76 }
77 
~InternalResponse()78 InternalResponse::~InternalResponse()
79 {
80 }
81 
82 template void
83 InternalResponse::ToIPC<PContentParent>
84   (IPCInternalResponse* aIPCResponse,
85    PContentParent* aManager,
86    UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream);
87 template void
88 InternalResponse::ToIPC<nsIContentChild>
89   (IPCInternalResponse* aIPCResponse,
90    nsIContentChild* aManager,
91    UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream);
92 template void
93 InternalResponse::ToIPC<mozilla::ipc::PBackgroundParent>
94   (IPCInternalResponse* aIPCResponse,
95    mozilla::ipc::PBackgroundParent* aManager,
96    UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream);
97 template void
98 InternalResponse::ToIPC<mozilla::ipc::PBackgroundChild>
99   (IPCInternalResponse* aIPCResponse,
100    mozilla::ipc::PBackgroundChild* aManager,
101    UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream);
102 
103 template<typename M>
104 void
ToIPC(IPCInternalResponse * aIPCResponse,M * aManager,UniquePtr<mozilla::ipc::AutoIPCStream> & aAutoStream)105 InternalResponse::ToIPC(IPCInternalResponse* aIPCResponse,
106                         M* aManager,
107                         UniquePtr<mozilla::ipc::AutoIPCStream>& aAutoStream)
108 {
109   MOZ_ASSERT(aIPCResponse);
110   aIPCResponse->type() = mType;
111   aIPCResponse->urlList() = mURLList;
112   aIPCResponse->status() = GetUnfilteredStatus();
113   aIPCResponse->statusText() = GetUnfilteredStatusText();
114 
115   mHeaders->ToIPC(aIPCResponse->headers(), aIPCResponse->headersGuard());
116 
117   aIPCResponse->channelInfo() = mChannelInfo.AsIPCChannelInfo();
118   if (mPrincipalInfo) {
119     aIPCResponse->principalInfo() = *mPrincipalInfo;
120   } else {
121     aIPCResponse->principalInfo() = void_t();
122   }
123 
124   nsCOMPtr<nsIInputStream> body;
125   int64_t bodySize;
126   GetUnfilteredBody(getter_AddRefs(body), &bodySize);
127 
128   if (body) {
129     aAutoStream.reset(new mozilla::ipc::AutoIPCStream(aIPCResponse->body()));
130     aAutoStream->Serialize(body, aManager);
131   } else {
132     aIPCResponse->body() = void_t();
133   }
134 
135   aIPCResponse->bodySize() = bodySize;
136 }
137 
138 already_AddRefed<InternalResponse>
Clone()139 InternalResponse::Clone()
140 {
141   RefPtr<InternalResponse> clone = CreateIncompleteCopy();
142 
143   clone->mHeaders = new InternalHeaders(*mHeaders);
144   if (mWrappedResponse) {
145     clone->mWrappedResponse = mWrappedResponse->Clone();
146     MOZ_ASSERT(!mBody);
147     return clone.forget();
148   }
149 
150   if (!mBody) {
151     return clone.forget();
152   }
153 
154   nsCOMPtr<nsIInputStream> clonedBody;
155   nsCOMPtr<nsIInputStream> replacementBody;
156 
157   nsresult rv = NS_CloneInputStream(mBody, getter_AddRefs(clonedBody),
158                                     getter_AddRefs(replacementBody));
159   if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; }
160 
161   clone->mBody.swap(clonedBody);
162   if (replacementBody) {
163     mBody.swap(replacementBody);
164   }
165 
166   return clone.forget();
167 }
168 
169 already_AddRefed<InternalResponse>
BasicResponse()170 InternalResponse::BasicResponse()
171 {
172   MOZ_ASSERT(!mWrappedResponse, "Can't BasicResponse a already wrapped response");
173   RefPtr<InternalResponse> basic = CreateIncompleteCopy();
174   basic->mType = ResponseType::Basic;
175   basic->mHeaders = InternalHeaders::BasicHeaders(Headers());
176   basic->mWrappedResponse = this;
177   return basic.forget();
178 }
179 
180 already_AddRefed<InternalResponse>
CORSResponse()181 InternalResponse::CORSResponse()
182 {
183   MOZ_ASSERT(!mWrappedResponse, "Can't CORSResponse a already wrapped response");
184   RefPtr<InternalResponse> cors = CreateIncompleteCopy();
185   cors->mType = ResponseType::Cors;
186   cors->mHeaders = InternalHeaders::CORSHeaders(Headers());
187   cors->mWrappedResponse = this;
188   return cors.forget();
189 }
190 
191 void
SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo)192 InternalResponse::SetPrincipalInfo(UniquePtr<mozilla::ipc::PrincipalInfo> aPrincipalInfo)
193 {
194   mPrincipalInfo = Move(aPrincipalInfo);
195 }
196 
197 LoadTainting
GetTainting() const198 InternalResponse::GetTainting() const
199 {
200   switch (mType) {
201     case ResponseType::Cors:
202       return LoadTainting::CORS;
203     case ResponseType::Opaque:
204       return LoadTainting::Opaque;
205     default:
206       return LoadTainting::Basic;
207   }
208 }
209 
210 already_AddRefed<InternalResponse>
Unfiltered()211 InternalResponse::Unfiltered()
212 {
213   RefPtr<InternalResponse> ref = mWrappedResponse;
214   if (!ref) {
215     ref = this;
216   }
217   return ref.forget();
218 }
219 
220 already_AddRefed<InternalResponse>
OpaqueResponse()221 InternalResponse::OpaqueResponse()
222 {
223   MOZ_ASSERT(!mWrappedResponse, "Can't OpaqueResponse a already wrapped response");
224   RefPtr<InternalResponse> response = new InternalResponse(0, EmptyCString());
225   response->mType = ResponseType::Opaque;
226   response->mTerminationReason = mTerminationReason;
227   response->mChannelInfo = mChannelInfo;
228   if (mPrincipalInfo) {
229     response->mPrincipalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(*mPrincipalInfo);
230   }
231   response->mWrappedResponse = this;
232   return response.forget();
233 }
234 
235 already_AddRefed<InternalResponse>
OpaqueRedirectResponse()236 InternalResponse::OpaqueRedirectResponse()
237 {
238   MOZ_ASSERT(!mWrappedResponse, "Can't OpaqueRedirectResponse a already wrapped response");
239   MOZ_ASSERT(!mURLList.IsEmpty(), "URLList should not be emtpy for internalResponse");
240   RefPtr<InternalResponse> response = OpaqueResponse();
241   response->mType = ResponseType::Opaqueredirect;
242   response->mURLList = mURLList;
243   return response.forget();
244 }
245 
246 already_AddRefed<InternalResponse>
CreateIncompleteCopy()247 InternalResponse::CreateIncompleteCopy()
248 {
249   RefPtr<InternalResponse> copy = new InternalResponse(mStatus, mStatusText);
250   copy->mType = mType;
251   copy->mTerminationReason = mTerminationReason;
252   copy->mURLList = mURLList;
253   copy->mChannelInfo = mChannelInfo;
254   if (mPrincipalInfo) {
255     copy->mPrincipalInfo = MakeUnique<mozilla::ipc::PrincipalInfo>(*mPrincipalInfo);
256   }
257   return copy.forget();
258 }
259 
260 } // namespace dom
261 } // namespace mozilla
262