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