1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et 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 // HttpLog.h should generally be included first
8 #include "HttpLog.h"
9
10 #include "mozilla/net/NeckoChannelParams.h" // For HttpActivityArgs.
11 #include "nsHttp.h"
12 #include "NullHttpTransaction.h"
13 #include "nsHttpHandler.h"
14 #include "nsHttpRequestHead.h"
15 #include "nsIHttpActivityObserver.h"
16 #include "nsQueryObject.h"
17 #include "nsNetUtil.h"
18
19 namespace mozilla {
20 namespace net {
21
NS_IMPL_ISUPPORTS(NullHttpTransaction,NullHttpTransaction,nsISupportsWeakReference)22 NS_IMPL_ISUPPORTS(NullHttpTransaction, NullHttpTransaction,
23 nsISupportsWeakReference)
24
25 NullHttpTransaction::NullHttpTransaction(nsHttpConnectionInfo* ci,
26 nsIInterfaceRequestor* callbacks,
27 uint32_t caps)
28 : mStatus(NS_OK),
29 mCaps(caps | NS_HTTP_ALLOW_KEEPALIVE),
30 mRequestHead(nullptr),
31 mIsDone(false),
32 mClaimed(false),
33 mCallbacks(callbacks),
34 mConnectionInfo(ci) {
35 nsresult rv;
36 mActivityDistributor =
37 do_GetService(NS_HTTPACTIVITYDISTRIBUTOR_CONTRACTID, &rv);
38 if (NS_FAILED(rv)) {
39 return;
40 }
41
42 bool activityDistributorActive;
43 rv = mActivityDistributor->GetIsActive(&activityDistributorActive);
44 if (NS_SUCCEEDED(rv) && activityDistributorActive) {
45 // There are some observers registered at activity distributor.
46 LOG(
47 ("NulHttpTransaction::NullHttpTransaction() "
48 "mActivityDistributor is active "
49 "[this=%p, %s]",
50 this, ci->GetOrigin().get()));
51 } else {
52 // There is no observer, so don't use it.
53 mActivityDistributor = nullptr;
54 }
55 }
56
~NullHttpTransaction()57 NullHttpTransaction::~NullHttpTransaction() {
58 mCallbacks = nullptr;
59 delete mRequestHead;
60 }
61
Claim()62 bool NullHttpTransaction::Claim() {
63 if (mClaimed) {
64 return false;
65 }
66 mClaimed = true;
67 return true;
68 }
69
Unclaim()70 void NullHttpTransaction::Unclaim() { mClaimed = false; }
71
SetConnection(nsAHttpConnection * conn)72 void NullHttpTransaction::SetConnection(nsAHttpConnection* conn) {
73 mConnection = conn;
74 }
75
Connection()76 nsAHttpConnection* NullHttpTransaction::Connection() {
77 return mConnection.get();
78 }
79
GetSecurityCallbacks(nsIInterfaceRequestor ** outCB)80 void NullHttpTransaction::GetSecurityCallbacks(nsIInterfaceRequestor** outCB) {
81 nsCOMPtr<nsIInterfaceRequestor> copyCB(mCallbacks);
82 *outCB = copyCB.forget().take();
83 }
84
OnTransportStatus(nsITransport * transport,nsresult status,int64_t progress)85 void NullHttpTransaction::OnTransportStatus(nsITransport* transport,
86 nsresult status, int64_t progress) {
87 if (status == NS_NET_STATUS_RESOLVING_HOST) {
88 if (mTimings.domainLookupStart.IsNull()) {
89 mTimings.domainLookupStart = TimeStamp::Now();
90 }
91 } else if (status == NS_NET_STATUS_RESOLVED_HOST) {
92 if (mTimings.domainLookupEnd.IsNull()) {
93 mTimings.domainLookupEnd = TimeStamp::Now();
94 }
95 } else if (status == NS_NET_STATUS_CONNECTING_TO) {
96 if (mTimings.connectStart.IsNull()) {
97 mTimings.connectStart = TimeStamp::Now();
98 }
99 } else if (status == NS_NET_STATUS_CONNECTED_TO) {
100 TimeStamp tnow = TimeStamp::Now();
101 if (mTimings.connectEnd.IsNull()) {
102 mTimings.connectEnd = tnow;
103 }
104 if (mTimings.tcpConnectEnd.IsNull()) {
105 mTimings.tcpConnectEnd = tnow;
106 }
107 } else if (status == NS_NET_STATUS_TLS_HANDSHAKE_STARTING) {
108 if (mTimings.secureConnectionStart.IsNull()) {
109 mTimings.secureConnectionStart = TimeStamp::Now();
110 }
111 } else if (status == NS_NET_STATUS_TLS_HANDSHAKE_ENDED) {
112 mTimings.connectEnd = TimeStamp::Now();
113 ;
114 }
115
116 if (mActivityDistributor) {
117 Unused << mActivityDistributor->ObserveActivityWithArgs(
118 HttpActivity(mConnectionInfo->GetOrigin(),
119 mConnectionInfo->OriginPort(),
120 mConnectionInfo->EndToEndSSL()),
121 NS_HTTP_ACTIVITY_TYPE_SOCKET_TRANSPORT, static_cast<uint32_t>(status),
122 PR_Now(), progress, ""_ns);
123 }
124 }
125
IsDone()126 bool NullHttpTransaction::IsDone() { return mIsDone; }
127
Status()128 nsresult NullHttpTransaction::Status() { return mStatus; }
129
Caps()130 uint32_t NullHttpTransaction::Caps() { return mCaps; }
131
ReadSegments(nsAHttpSegmentReader * reader,uint32_t count,uint32_t * countRead)132 nsresult NullHttpTransaction::ReadSegments(nsAHttpSegmentReader* reader,
133 uint32_t count,
134 uint32_t* countRead) {
135 *countRead = 0;
136 mIsDone = true;
137 return NS_BASE_STREAM_CLOSED;
138 }
139
WriteSegments(nsAHttpSegmentWriter * writer,uint32_t count,uint32_t * countWritten)140 nsresult NullHttpTransaction::WriteSegments(nsAHttpSegmentWriter* writer,
141 uint32_t count,
142 uint32_t* countWritten) {
143 *countWritten = 0;
144 return NS_BASE_STREAM_CLOSED;
145 }
146
Http1xTransactionCount()147 uint32_t NullHttpTransaction::Http1xTransactionCount() { return 0; }
148
RequestHead()149 nsHttpRequestHead* NullHttpTransaction::RequestHead() {
150 // We suport a requesthead at all so that a CONNECT tunnel transaction
151 // can obtain a Host header from it, but we lazy-popualate that header.
152
153 if (!mRequestHead) {
154 mRequestHead = new nsHttpRequestHead();
155
156 nsAutoCString hostHeader;
157 nsCString host(mConnectionInfo->GetOrigin());
158 nsresult rv = nsHttpHandler::GenerateHostPort(
159 host, mConnectionInfo->OriginPort(), hostHeader);
160 if (NS_SUCCEEDED(rv)) {
161 rv = mRequestHead->SetHeader(nsHttp::Host, hostHeader);
162 MOZ_ASSERT(NS_SUCCEEDED(rv));
163 if (mActivityDistributor) {
164 // Report request headers.
165 nsCString reqHeaderBuf;
166 mRequestHead->Flatten(reqHeaderBuf, false);
167 Unused << mActivityDistributor->ObserveActivityWithArgs(
168 HttpActivity(mConnectionInfo->GetOrigin(),
169 mConnectionInfo->OriginPort(),
170 mConnectionInfo->EndToEndSSL()),
171 NS_HTTP_ACTIVITY_TYPE_HTTP_TRANSACTION,
172 NS_HTTP_ACTIVITY_SUBTYPE_REQUEST_HEADER, PR_Now(), 0, reqHeaderBuf);
173 }
174 }
175
176 // CONNECT tunnels may also want Proxy-Authorization but that is a lot
177 // harder to determine, so for now we will let those connections fail in
178 // the NullHttpTransaction and let them be retried from the pending queue
179 // with a bound transaction
180 }
181
182 return mRequestHead;
183 }
184
TakeSubTransactions(nsTArray<RefPtr<nsAHttpTransaction>> & outTransactions)185 nsresult NullHttpTransaction::TakeSubTransactions(
186 nsTArray<RefPtr<nsAHttpTransaction> >& outTransactions) {
187 return NS_ERROR_NOT_IMPLEMENTED;
188 }
189
SetProxyConnectFailed()190 void NullHttpTransaction::SetProxyConnectFailed() {}
191
Close(nsresult reason)192 void NullHttpTransaction::Close(nsresult reason) {
193 mStatus = reason;
194 mConnection = nullptr;
195 mIsDone = true;
196 if (mActivityDistributor) {
197 // Report that this transaction is closing.
198 Unused << mActivityDistributor->ObserveActivityWithArgs(
199 HttpActivity(mConnectionInfo->GetOrigin(),
200 mConnectionInfo->OriginPort(),
201 mConnectionInfo->EndToEndSSL()),
202 NS_HTTP_ACTIVITY_TYPE_HTTP_TRANSACTION,
203 NS_HTTP_ACTIVITY_SUBTYPE_TRANSACTION_CLOSE, PR_Now(), 0, ""_ns);
204 }
205 }
206
ConnectionInfo()207 nsHttpConnectionInfo* NullHttpTransaction::ConnectionInfo() {
208 return mConnectionInfo;
209 }
210
211 } // namespace net
212 } // namespace mozilla
213