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