15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_request_redirect_job.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <string>
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/logging.h"
129ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/strings/stringprintf.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/base/load_timing_info.h"
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/base/net_errors.h"
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/base/net_log.h"
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/http/http_response_headers.h"
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/http/http_util.h"
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "net/url_request/url_request.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLRequestRedirectJob::URLRequestRedirectJob(URLRequest* request,
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             NetworkDelegate* network_delegate,
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                             const GURL& redirect_destination,
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                             ResponseCode response_code,
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                             const std::string& redirect_reason)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : URLRequestJob(request, network_delegate),
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      redirect_destination_(redirect_destination),
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      response_code_(response_code),
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      redirect_reason_(redirect_reason),
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      weak_factory_(this) {
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  DCHECK(!redirect_reason_.empty());
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void URLRequestRedirectJob::GetResponseInfo(HttpResponseInfo* info) {
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Should only be called after the URLRequest has been notified there's header
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // information.
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(fake_headers_.get());
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // This assumes |info| is a freshly constructed HttpResponseInfo.
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  info->headers = fake_headers_;
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  info->request_time = response_time_;
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  info->response_time = response_time_;
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void URLRequestRedirectJob::GetLoadTimingInfo(
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    LoadTimingInfo* load_timing_info) const {
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Set send_start and send_end to receive_headers_end_ to be consistent
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // with network cache behavior.
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  load_timing_info->send_start = receive_headers_end_;
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  load_timing_info->send_end = receive_headers_end_;
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  load_timing_info->receive_headers_end = receive_headers_end_;
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestRedirectJob::Start() {
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  request()->net_log().AddEvent(
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      NetLog::TYPE_URL_REQUEST_REDIRECT_JOB,
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      NetLog::StringCallback("reason", &redirect_reason_));
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&URLRequestRedirectJob::StartAsync,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 weak_factory_.GetWeakPtr()));
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
66c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochbool URLRequestRedirectJob::CopyFragmentOnRedirect(const GURL& location) const {
67c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // The instantiators have full control over the desired redirection target,
68c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // including the reference fragment part of the URL.
69c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  return false;
70c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
71c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)int URLRequestRedirectJob::GetResponseCode() const {
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Should only be called after the URLRequest has been notified there's header
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // information.
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(fake_headers_.get());
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return response_code_;
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)URLRequestRedirectJob::~URLRequestRedirectJob() {}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void URLRequestRedirectJob::StartAsync() {
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  receive_headers_end_ = base::TimeTicks::Now();
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  response_time_ = base::Time::Now();
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string header_string =
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::StringPrintf("HTTP/1.1 %i Internal Redirect\n"
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                             "Location: %s\n"
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                             "Non-Authoritative-Reason: %s",
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         response_code_,
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         redirect_destination_.spec().c_str(),
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                         redirect_reason_.c_str());
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string http_origin;
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const net::HttpRequestHeaders& request_headers =
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      request_->extra_request_headers();
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (request_headers.GetHeader("Origin", &http_origin)) {
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // If this redirect is used in a cross-origin request, add CORS headers to
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // make sure that the redirect gets through. Note that the destination URL
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // is still subject to the usual CORS policy, i.e. the resource will only
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // be available to web pages if the server serves the response with the
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // required CORS response headers.
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    header_string += base::StringPrintf(
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        "\n"
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        "Access-Control-Allow-Origin: %s\n"
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        "Access-Control-Allow-Credentials: true",
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        http_origin.c_str());
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  fake_headers_ = new HttpResponseHeaders(
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      HttpUtil::AssembleRawHeaders(header_string.c_str(),
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                   header_string.length()));
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(fake_headers_->IsRedirect(NULL));
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  request()->net_log().AddEvent(
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NetLog::TYPE_URL_REQUEST_FAKE_RESPONSE_HEADERS_CREATED,
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          &HttpResponseHeaders::NetLogCallback,
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          base::Unretained(fake_headers_.get())));
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // TODO(mmenke):  Consider calling the NetworkDelegate with the headers here.
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // There's some weirdness about how to handle the case in which the delegate
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // tries to modify the redirect location, in terms of how IsSafeRedirect
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // should behave, and whether the fragment should be copied.
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  URLRequestJob::NotifyHeadersComplete();
125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
128