summaryrefslogtreecommitdiffstats
path: root/components/html_viewer/blink_url_request_type_converters.cc
blob: 339db95c79c6ce145cd10fd742db41168426a64d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/html_viewer/blink_url_request_type_converters.h"

#include "base/strings/string_util.h"
#include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/mojo/src/mojo/public/cpp/system/data_pipe.h"

namespace mojo {
namespace {

// Ripped from web_url_loader_impl.cc.
class HeaderFlattener : public blink::WebHTTPHeaderVisitor {
 public:
  HeaderFlattener() : has_accept_header_(false) {}

  void visitHeader(const blink::WebString& name,
                   const blink::WebString& value) override {
    // Headers are latin1.
    const std::string& name_latin1 = name.latin1();
    const std::string& value_latin1 = value.latin1();

    if (base::LowerCaseEqualsASCII(name_latin1, "accept"))
      has_accept_header_ = true;

    HttpHeaderPtr header = HttpHeader::New();
    header->name = name_latin1;
    header->value = value_latin1;
    buffer_.push_back(header.Pass());
  }

  Array<HttpHeaderPtr> GetBuffer() {
    // In some cases, WebKit doesn't add an Accept header, but not having the
    // header confuses some web servers.  See bug 808613.
    if (!has_accept_header_) {
      HttpHeaderPtr header = HttpHeader::New();
      header->name = "Accept";
      header->value = "*/*";
      buffer_.push_back(header.Pass());
      has_accept_header_ = true;
    }
    return buffer_.Pass();
  }

 private:
  Array<HttpHeaderPtr> buffer_;
  bool has_accept_header_;
};

void AddRequestBody(URLRequest* url_request,
                    const blink::WebURLRequest& request) {
  if (request.httpBody().isNull())
    return;

  uint32_t i = 0;
  blink::WebHTTPBody::Element element;
  while (request.httpBody().elementAt(i++, element)) {
    switch (element.type) {
      case blink::WebHTTPBody::Element::TypeData:
        if (!element.data.isEmpty()) {
          // WebKit sometimes gives up empty data to append. These aren't
          // necessary so we just optimize those out here.
          uint32_t num_bytes = static_cast<uint32_t>(element.data.size());
          MojoCreateDataPipeOptions options;
          options.struct_size = sizeof(MojoCreateDataPipeOptions);
          options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE;
          options.element_num_bytes = 1;
          options.capacity_num_bytes = num_bytes;
          DataPipe data_pipe(options);
          url_request->body.push_back(
              data_pipe.consumer_handle.Pass());
          WriteDataRaw(data_pipe.producer_handle.get(),
                       element.data.data(),
                       &num_bytes,
                       MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
        }
        break;
      case blink::WebHTTPBody::Element::TypeFile:
      case blink::WebHTTPBody::Element::TypeFileSystemURL:
      case blink::WebHTTPBody::Element::TypeBlob:
        // TODO(mpcomplete): handle these.
        NOTIMPLEMENTED();
        break;
      default:
        NOTREACHED();
    }
  }
}

} // namespace

URLRequestPtr TypeConverter<URLRequestPtr, blink::WebURLRequest>::Convert(
    const blink::WebURLRequest& request) {
  URLRequestPtr url_request(URLRequest::New());
  url_request->url = request.url().string().utf8();
  url_request->method = request.httpMethod().utf8();

  HeaderFlattener flattener;
  request.visitHTTPHeaderFields(&flattener);
  url_request->headers = flattener.GetBuffer().Pass();

  AddRequestBody(url_request.get(), request);

  return url_request.Pass();
}

}  // namespace mojo