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