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