Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/protocol/http/NullHttpTransaction.cpp
Line
Count
Source (jump to first uncovered line)
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 "nsHttp.h"
11
#include "NullHttpTransaction.h"
12
#include "nsHttpHandler.h"
13
#include "nsHttpRequestHead.h"
14
#include "nsIHttpActivityObserver.h"
15
#include "NullHttpChannel.h"
16
#include "nsQueryObject.h"
17
#include "nsNetUtil.h"
18
#include "TCPFastOpenLayer.h"
19
20
namespace mozilla {
21
namespace net {
22
23
class CallObserveActivity final : public nsIRunnable
24
{
25
0
  ~CallObserveActivity() = default;
26
public:
27
  NS_DECL_THREADSAFE_ISUPPORTS
28
  CallObserveActivity(nsIHttpActivityObserver *aActivityDistributor,
29
                      const nsCString &aHost,
30
                      int32_t aPort,
31
                      bool aEndToEndSSL,
32
                      uint32_t aActivityType,
33
                      uint32_t aActivitySubtype,
34
                      PRTime aTimestamp,
35
                      uint64_t aExtraSizeData,
36
                      const nsACString &aExtraStringData)
37
    : mActivityDistributor(aActivityDistributor)
38
    , mHost(aHost)
39
    , mPort(aPort)
40
    , mEndToEndSSL(aEndToEndSSL)
41
    , mActivityType(aActivityType)
42
    , mActivitySubtype(aActivitySubtype)
43
    , mTimestamp(aTimestamp)
44
    , mExtraSizeData(aExtraSizeData)
45
    , mExtraStringData(aExtraStringData)
46
0
  {
47
0
  }
48
  NS_IMETHOD Run() override
49
0
  {
50
0
    MOZ_ASSERT(NS_IsMainThread());
51
0
    nsCOMPtr<nsIURI> uri;
52
0
    nsAutoCString port(NS_LITERAL_CSTRING(""));
53
0
    if (mPort != -1 && ((mEndToEndSSL && mPort != 443) ||
54
0
        (!mEndToEndSSL && mPort != 80))) {
55
0
      port.AppendInt(mPort);
56
0
    }
57
0
58
0
    nsresult rv = NS_NewURI(getter_AddRefs(uri),
59
0
                            (mEndToEndSSL ? NS_LITERAL_CSTRING("https://")
60
0
                            : NS_LITERAL_CSTRING("http://") ) + mHost + port);
61
0
    if (NS_FAILED(rv)) {
62
0
      return NS_OK;
63
0
    }
64
0
65
0
    RefPtr<NullHttpChannel> channel = new NullHttpChannel();
66
0
    rv = channel->Init(uri, 0, nullptr, 0, nullptr);
67
0
    MOZ_ASSERT(NS_SUCCEEDED(rv));
68
0
    rv = mActivityDistributor->ObserveActivity(
69
0
      nsCOMPtr<nsISupports>(do_QueryObject(channel)),
70
0
      mActivityType,
71
0
      mActivitySubtype,
72
0
      mTimestamp,
73
0
      mExtraSizeData,
74
0
      mExtraStringData);
75
0
    NS_ENSURE_SUCCESS(rv, rv);
76
0
77
0
    return NS_OK;
78
0
  }
79
private:
80
  nsCOMPtr<nsIHttpActivityObserver> mActivityDistributor;
81
  nsCString mHost;
82
  int32_t mPort;
83
  bool mEndToEndSSL;
84
  uint32_t mActivityType;
85
  uint32_t mActivitySubtype;
86
  PRTime mTimestamp;
87
  uint64_t mExtraSizeData;
88
  nsCString mExtraStringData;
89
};
90
91
NS_IMPL_ISUPPORTS(CallObserveActivity, nsIRunnable)
92
93
NS_IMPL_ISUPPORTS(NullHttpTransaction, NullHttpTransaction, nsISupportsWeakReference)
94
95
NullHttpTransaction::NullHttpTransaction(nsHttpConnectionInfo *ci,
96
                                         nsIInterfaceRequestor *callbacks,
97
                                         uint32_t caps)
98
  : mStatus(NS_OK)
99
  , mCaps(caps | NS_HTTP_ALLOW_KEEPALIVE)
100
  , mRequestHead(nullptr)
101
  , mCapsToClear(0)
102
  , mIsDone(false)
103
  , mClaimed(false)
104
  , mFastOpenStatus(TFO_NOT_TRIED)
105
  , mCallbacks(callbacks)
106
  , mConnectionInfo(ci)
107
0
{
108
0
  nsresult rv;
109
0
  mActivityDistributor = do_GetService(NS_HTTPACTIVITYDISTRIBUTOR_CONTRACTID,
110
0
                                       &rv);
111
0
  if (NS_FAILED(rv)) {
112
0
    return;
113
0
  }
114
0
115
0
  bool activityDistributorActive;
116
0
  rv = mActivityDistributor->GetIsActive(&activityDistributorActive);
117
0
  if (NS_SUCCEEDED(rv) && activityDistributorActive) {
118
0
    // There are some observers registered at activity distributor.
119
0
    LOG(("NulHttpTransaction::NullHttpTransaction() "
120
0
         "mActivityDistributor is active "
121
0
         "[this=%p, %s]", this, ci->GetOrigin().get()));
122
0
  } else {
123
0
    // There is no observer, so don't use it.
124
0
    mActivityDistributor = nullptr;
125
0
  }
126
0
}
127
128
NullHttpTransaction::~NullHttpTransaction()
129
0
{
130
0
  mCallbacks = nullptr;
131
0
  delete mRequestHead;
132
0
}
133
134
bool
135
NullHttpTransaction::Claim()
136
0
{
137
0
  if (mClaimed) {
138
0
    return false;
139
0
  }
140
0
  mClaimed = true;
141
0
  return true;
142
0
}
143
144
void
145
NullHttpTransaction::Unclaim()
146
0
{
147
0
  mClaimed = false;
148
0
}
149
150
void
151
NullHttpTransaction::SetConnection(nsAHttpConnection *conn)
152
0
{
153
0
  mConnection = conn;
154
0
}
155
156
nsAHttpConnection *
157
NullHttpTransaction::Connection()
158
0
{
159
0
  return mConnection.get();
160
0
}
161
162
void
163
NullHttpTransaction::GetSecurityCallbacks(nsIInterfaceRequestor **outCB)
164
0
{
165
0
  nsCOMPtr<nsIInterfaceRequestor> copyCB(mCallbacks);
166
0
  *outCB = copyCB.forget().take();
167
0
}
168
169
void
170
NullHttpTransaction::OnTransportStatus(nsITransport* transport,
171
                                       nsresult status, int64_t progress)
172
0
{
173
0
  if (status == NS_NET_STATUS_RESOLVING_HOST) {
174
0
    if (mTimings.domainLookupStart.IsNull()) {
175
0
      mTimings.domainLookupStart = TimeStamp::Now();
176
0
    }
177
0
  } else if (status == NS_NET_STATUS_RESOLVED_HOST) {
178
0
    if (mTimings.domainLookupEnd.IsNull()) {
179
0
      mTimings.domainLookupEnd = TimeStamp::Now();
180
0
    }
181
0
  } else if (status == NS_NET_STATUS_CONNECTING_TO) {
182
0
    if (mTimings.connectStart.IsNull()) {
183
0
      mTimings.connectStart = TimeStamp::Now();
184
0
    }
185
0
  } else if (status == NS_NET_STATUS_CONNECTED_TO) {
186
0
    TimeStamp tnow = TimeStamp::Now();
187
0
    if (mTimings.connectEnd.IsNull()) {
188
0
        mTimings.connectEnd = tnow;
189
0
    }
190
0
    if (mTimings.tcpConnectEnd.IsNull()) {
191
0
        mTimings.tcpConnectEnd = tnow;
192
0
    }
193
0
    // After a socket is connected we know for sure whether data has been
194
0
    // sent on SYN packet and if not we should update TLS start timing.
195
0
    if ((mFastOpenStatus != TFO_DATA_SENT) &&
196
0
        !mTimings.secureConnectionStart.IsNull()) {
197
0
        mTimings.secureConnectionStart = tnow;
198
0
    }
199
0
  } else if (status == NS_NET_STATUS_TLS_HANDSHAKE_STARTING) {
200
0
    if (mTimings.secureConnectionStart.IsNull()) {
201
0
        mTimings.secureConnectionStart = TimeStamp::Now();
202
0
    }
203
0
  } else if (status == NS_NET_STATUS_TLS_HANDSHAKE_ENDED) {
204
0
    mTimings.connectEnd = TimeStamp::Now();;
205
0
  }
206
0
207
0
  if (mActivityDistributor) {
208
0
    NS_DispatchToMainThread(new CallObserveActivity(mActivityDistributor,
209
0
                                  mConnectionInfo->GetOrigin(),
210
0
                                  mConnectionInfo->OriginPort(),
211
0
                                  mConnectionInfo->EndToEndSSL(),
212
0
                                  NS_HTTP_ACTIVITY_TYPE_SOCKET_TRANSPORT,
213
0
                                  static_cast<uint32_t>(status),
214
0
                                  PR_Now(),
215
0
                                  progress,
216
0
                                  EmptyCString()));
217
0
  }
218
0
}
219
220
bool
221
NullHttpTransaction::IsDone()
222
0
{
223
0
  return mIsDone;
224
0
}
225
226
nsresult
227
NullHttpTransaction::Status()
228
0
{
229
0
  return mStatus;
230
0
}
231
232
uint32_t
233
NullHttpTransaction::Caps()
234
0
{
235
0
  return mCaps & ~mCapsToClear;
236
0
}
237
238
void
239
NullHttpTransaction::SetDNSWasRefreshed()
240
0
{
241
0
  MOZ_ASSERT(NS_IsMainThread(), "SetDNSWasRefreshed on main thread only!");
242
0
  mCapsToClear |= NS_HTTP_REFRESH_DNS;
243
0
}
244
245
nsresult
246
NullHttpTransaction::ReadSegments(nsAHttpSegmentReader *reader,
247
                                  uint32_t count, uint32_t *countRead)
248
0
{
249
0
  *countRead = 0;
250
0
  mIsDone = true;
251
0
  return NS_BASE_STREAM_CLOSED;
252
0
}
253
254
nsresult
255
NullHttpTransaction::WriteSegments(nsAHttpSegmentWriter *writer,
256
                                   uint32_t count, uint32_t *countWritten)
257
0
{
258
0
  *countWritten = 0;
259
0
  return NS_BASE_STREAM_CLOSED;
260
0
}
261
262
uint32_t
263
NullHttpTransaction::Http1xTransactionCount()
264
0
{
265
0
  return 0;
266
0
}
267
268
nsHttpRequestHead *
269
NullHttpTransaction::RequestHead()
270
0
{
271
0
  // We suport a requesthead at all so that a CONNECT tunnel transaction
272
0
  // can obtain a Host header from it, but we lazy-popualate that header.
273
0
274
0
  if (!mRequestHead) {
275
0
    mRequestHead = new nsHttpRequestHead();
276
0
277
0
    nsAutoCString hostHeader;
278
0
    nsCString host(mConnectionInfo->GetOrigin());
279
0
    nsresult rv = nsHttpHandler::GenerateHostPort(host,
280
0
                                                  mConnectionInfo->OriginPort(),
281
0
                                                  hostHeader);
282
0
    if (NS_SUCCEEDED(rv)) {
283
0
      rv = mRequestHead->SetHeader(nsHttp::Host, hostHeader);
284
0
      MOZ_ASSERT(NS_SUCCEEDED(rv));
285
0
      if (mActivityDistributor) {
286
0
        // Report request headers.
287
0
        nsCString reqHeaderBuf;
288
0
        mRequestHead->Flatten(reqHeaderBuf, false);
289
0
        NS_DispatchToMainThread(new CallObserveActivity(mActivityDistributor,
290
0
                                  mConnectionInfo->GetOrigin(),
291
0
                                  mConnectionInfo->OriginPort(),
292
0
                                  mConnectionInfo->EndToEndSSL(),
293
0
                                  NS_HTTP_ACTIVITY_TYPE_HTTP_TRANSACTION,
294
0
                                  NS_HTTP_ACTIVITY_SUBTYPE_REQUEST_HEADER,
295
0
                                  PR_Now(), 0, reqHeaderBuf));
296
0
    }
297
0
  }
298
0
299
0
    // CONNECT tunnels may also want Proxy-Authorization but that is a lot
300
0
    // harder to determine, so for now we will let those connections fail in
301
0
    // the NullHttpTransaction and let them be retried from the pending queue
302
0
    // with a bound transaction
303
0
  }
304
0
305
0
  return mRequestHead;
306
0
}
307
308
nsresult
309
NullHttpTransaction::TakeSubTransactions(
310
  nsTArray<RefPtr<nsAHttpTransaction> > &outTransactions)
311
0
{
312
0
  return NS_ERROR_NOT_IMPLEMENTED;
313
0
}
314
315
void
316
NullHttpTransaction::SetProxyConnectFailed()
317
0
{
318
0
}
319
320
void
321
NullHttpTransaction::Close(nsresult reason)
322
0
{
323
0
  mStatus = reason;
324
0
  mConnection = nullptr;
325
0
  mIsDone = true;
326
0
  if (mActivityDistributor) {
327
0
    // Report that this transaction is closing.
328
0
    NS_DispatchToMainThread(new CallObserveActivity(mActivityDistributor,
329
0
                                  mConnectionInfo->GetOrigin(),
330
0
                                  mConnectionInfo->OriginPort(),
331
0
                                  mConnectionInfo->EndToEndSSL(),
332
0
                                  NS_HTTP_ACTIVITY_TYPE_HTTP_TRANSACTION,
333
0
                                  NS_HTTP_ACTIVITY_SUBTYPE_TRANSACTION_CLOSE,
334
0
                                  PR_Now(), 0, EmptyCString()));
335
0
  }
336
0
}
337
338
nsHttpConnectionInfo *
339
NullHttpTransaction::ConnectionInfo()
340
0
{
341
0
  return mConnectionInfo;
342
0
}
343
344
} // namespace net
345
} // namespace mozilla
346