1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "content/renderer/fetchers/resource_fetcher_impl.h"
6
7#include "base/logging.h"
8#include "base/strings/string_util.h"
9#include "base/time/time.h"
10#include "third_party/WebKit/public/platform/Platform.h"
11#include "third_party/WebKit/public/platform/WebHTTPBody.h"
12#include "third_party/WebKit/public/platform/WebURL.h"
13#include "third_party/WebKit/public/platform/WebURLError.h"
14#include "third_party/WebKit/public/platform/WebURLLoader.h"
15#include "third_party/WebKit/public/platform/WebURLRequest.h"
16#include "third_party/WebKit/public/web/WebDocument.h"
17#include "third_party/WebKit/public/web/WebFrame.h"
18#include "third_party/WebKit/public/web/WebKit.h"
19#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
20
21using base::TimeDelta;
22using blink::WebFrame;
23using blink::WebHTTPBody;
24using blink::WebSecurityPolicy;
25using blink::WebURLError;
26using blink::WebURLLoader;
27using blink::WebURLRequest;
28using blink::WebURLResponse;
29
30namespace content {
31
32// static
33ResourceFetcher* ResourceFetcher::Create(const GURL& url) {
34  return new ResourceFetcherImpl(url);
35}
36
37ResourceFetcherImpl::ResourceFetcherImpl(const GURL& url)
38    : request_(url) {
39}
40
41ResourceFetcherImpl::~ResourceFetcherImpl() {
42  if (!completed() && loader_)
43    loader_->cancel();
44}
45
46void ResourceFetcherImpl::SetMethod(const std::string& method) {
47  DCHECK(!request_.isNull());
48  DCHECK(!loader_);
49
50  request_.setHTTPMethod(blink::WebString::fromUTF8(method));
51}
52
53void ResourceFetcherImpl::SetBody(const std::string& body) {
54  DCHECK(!request_.isNull());
55  DCHECK(!loader_);
56
57  WebHTTPBody web_http_body;
58  web_http_body.initialize();
59  web_http_body.appendData(blink::WebData(body));
60  request_.setHTTPBody(web_http_body);
61}
62
63void ResourceFetcherImpl::SetHeader(const std::string& header,
64                                    const std::string& value) {
65  DCHECK(!request_.isNull());
66  DCHECK(!loader_);
67
68  if (LowerCaseEqualsASCII(header, "referer")) {
69    blink::WebString referrer = WebSecurityPolicy::generateReferrerHeader(
70        blink::WebReferrerPolicyDefault,
71        request_.url(),
72        blink::WebString::fromUTF8(value));
73    request_.setHTTPReferrer(referrer, blink::WebReferrerPolicyDefault);
74  } else {
75    request_.setHTTPHeaderField(blink::WebString::fromUTF8(header),
76                                blink::WebString::fromUTF8(value));
77  }
78}
79
80void ResourceFetcherImpl::Start(WebFrame* frame,
81                                WebURLRequest::RequestContext request_context,
82                                WebURLRequest::FrameType frame_type,
83                                LoaderType loader_type,
84                                const Callback& callback) {
85  DCHECK(!loader_);
86  DCHECK(!request_.isNull());
87  DCHECK(callback_.is_null());
88  DCHECK(!completed());
89  if (!request_.httpBody().isNull())
90    DCHECK_NE("GET", request_.httpMethod().utf8()) << "GETs can't have bodies.";
91
92  callback_ = callback;
93
94  request_.setRequestContext(request_context);
95  request_.setFrameType(frame_type);
96  request_.setFirstPartyForCookies(frame->document().firstPartyForCookies());
97  frame->dispatchWillSendRequest(request_);
98
99  switch (loader_type) {
100    case PLATFORM_LOADER:
101      loader_.reset(blink::Platform::current()->createURLLoader());
102      break;
103    case FRAME_ASSOCIATED_LOADER:
104      loader_.reset(frame->createAssociatedURLLoader());
105      break;
106  }
107  loader_->loadAsynchronously(request_, this);
108
109  // No need to hold on to the request.
110  request_.reset();
111}
112
113void ResourceFetcherImpl::SetTimeout(const base::TimeDelta& timeout) {
114  DCHECK(loader_);
115  DCHECK(!completed());
116
117  timeout_timer_.Start(FROM_HERE, timeout, this, &ResourceFetcherImpl::Cancel);
118}
119
120void ResourceFetcherImpl::OnLoadComplete() {
121  timeout_timer_.Stop();
122  if (callback_.is_null())
123    return;
124
125  // Take a reference to the callback as running the callback may lead to our
126  // destruction.
127  Callback callback = callback_;
128  callback.Run(status() == LOAD_FAILED ? blink::WebURLResponse() : response(),
129               status() == LOAD_FAILED ? std::string() : data());
130}
131
132void ResourceFetcherImpl::Cancel() {
133  loader_->cancel();
134  WebURLLoaderClientImpl::Cancel();
135}
136
137}  // namespace content
138