Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / url_request / url_request_redirect_job.cc
blob1dfb56dc083cece2c6bc3b79289fa6b08f2cfd6b
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.
5 #include "net/url_request/url_request_redirect_job.h"
7 #include <string>
9 #include "base/bind.h"
10 #include "base/compiler_specific.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "base/values.h"
17 #include "net/base/load_timing_info.h"
18 #include "net/base/net_errors.h"
19 #include "net/http/http_response_headers.h"
20 #include "net/http/http_util.h"
21 #include "net/log/net_log.h"
22 #include "net/url_request/url_request.h"
24 namespace net {
26 URLRequestRedirectJob::URLRequestRedirectJob(URLRequest* request,
27 NetworkDelegate* network_delegate,
28 const GURL& redirect_destination,
29 ResponseCode response_code,
30 const std::string& redirect_reason)
31 : URLRequestJob(request, network_delegate),
32 redirect_destination_(redirect_destination),
33 response_code_(response_code),
34 redirect_reason_(redirect_reason),
35 weak_factory_(this) {
36 DCHECK(!redirect_reason_.empty());
39 void URLRequestRedirectJob::GetResponseInfo(HttpResponseInfo* info) {
40 // Should only be called after the URLRequest has been notified there's header
41 // information.
42 DCHECK(fake_headers_.get());
44 // This assumes |info| is a freshly constructed HttpResponseInfo.
45 info->headers = fake_headers_;
46 info->request_time = response_time_;
47 info->response_time = response_time_;
50 void URLRequestRedirectJob::GetLoadTimingInfo(
51 LoadTimingInfo* load_timing_info) const {
52 // Set send_start and send_end to receive_headers_end_ to be consistent
53 // with network cache behavior.
54 load_timing_info->send_start = receive_headers_end_;
55 load_timing_info->send_end = receive_headers_end_;
56 load_timing_info->receive_headers_end = receive_headers_end_;
59 void URLRequestRedirectJob::Start() {
60 request()->net_log().AddEvent(
61 NetLog::TYPE_URL_REQUEST_REDIRECT_JOB,
62 NetLog::StringCallback("reason", &redirect_reason_));
63 base::ThreadTaskRunnerHandle::Get()->PostTask(
64 FROM_HERE, base::Bind(&URLRequestRedirectJob::StartAsync,
65 weak_factory_.GetWeakPtr()));
68 void URLRequestRedirectJob::Kill() {
69 weak_factory_.InvalidateWeakPtrs();
70 URLRequestJob::Kill();
73 bool URLRequestRedirectJob::CopyFragmentOnRedirect(const GURL& location) const {
74 // The instantiators have full control over the desired redirection target,
75 // including the reference fragment part of the URL.
76 return false;
79 int URLRequestRedirectJob::GetResponseCode() const {
80 // Should only be called after the URLRequest has been notified there's header
81 // information.
82 DCHECK(fake_headers_.get());
83 return response_code_;
86 URLRequestRedirectJob::~URLRequestRedirectJob() {}
88 void URLRequestRedirectJob::StartAsync() {
89 DCHECK(request_);
90 DCHECK(request_->status().is_success());
92 receive_headers_end_ = base::TimeTicks::Now();
93 response_time_ = base::Time::Now();
95 std::string header_string =
96 base::StringPrintf("HTTP/1.1 %i Internal Redirect\n"
97 "Location: %s\n"
98 "Non-Authoritative-Reason: %s",
99 response_code_,
100 redirect_destination_.spec().c_str(),
101 redirect_reason_.c_str());
103 std::string http_origin;
104 const HttpRequestHeaders& request_headers = request_->extra_request_headers();
105 if (request_headers.GetHeader("Origin", &http_origin)) {
106 // If this redirect is used in a cross-origin request, add CORS headers to
107 // make sure that the redirect gets through. Note that the destination URL
108 // is still subject to the usual CORS policy, i.e. the resource will only
109 // be available to web pages if the server serves the response with the
110 // required CORS response headers.
111 header_string += base::StringPrintf(
112 "\n"
113 "Access-Control-Allow-Origin: %s\n"
114 "Access-Control-Allow-Credentials: true",
115 http_origin.c_str());
118 fake_headers_ = new HttpResponseHeaders(
119 HttpUtil::AssembleRawHeaders(header_string.c_str(),
120 header_string.length()));
121 DCHECK(fake_headers_->IsRedirect(NULL));
123 request()->net_log().AddEvent(
124 NetLog::TYPE_URL_REQUEST_FAKE_RESPONSE_HEADERS_CREATED,
125 base::Bind(
126 &HttpResponseHeaders::NetLogCallback,
127 base::Unretained(fake_headers_.get())));
129 // TODO(mmenke): Consider calling the NetworkDelegate with the headers here.
130 // There's some weirdness about how to handle the case in which the delegate
131 // tries to modify the redirect location, in terms of how IsSafeRedirect
132 // should behave, and whether the fragment should be copied.
133 URLRequestJob::NotifyHeadersComplete();
136 } // namespace net