1// Copyright 2014 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 "mojo/services/html_viewer/blink_url_request_type_converters.h" 6 7#include "base/strings/string_util.h" 8#include "mojo/public/cpp/system/data_pipe.h" 9#include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h" 10#include "third_party/WebKit/public/platform/WebURLRequest.h" 11 12namespace mojo { 13namespace { 14 15// Ripped from web_url_loader_impl.cc. 16class HeaderFlattener : public blink::WebHTTPHeaderVisitor { 17 public: 18 HeaderFlattener() : has_accept_header_(false) {} 19 20 virtual void visitHeader(const blink::WebString& name, 21 const blink::WebString& value) { 22 // Headers are latin1. 23 const std::string& name_latin1 = name.latin1(); 24 const std::string& value_latin1 = value.latin1(); 25 26 // Skip over referrer headers found in the header map because we already 27 // pulled it out as a separate parameter. 28 if (LowerCaseEqualsASCII(name_latin1, "referer")) 29 return; 30 31 if (LowerCaseEqualsASCII(name_latin1, "accept")) 32 has_accept_header_ = true; 33 34 buffer_.push_back(name_latin1 + ": " + value_latin1); 35 } 36 37 Array<String> GetBuffer() { 38 // In some cases, WebKit doesn't add an Accept header, but not having the 39 // header confuses some web servers. See bug 808613. 40 if (!has_accept_header_) { 41 buffer_.push_back("Accept: */*"); 42 has_accept_header_ = true; 43 } 44 return buffer_.Pass(); 45 } 46 47 private: 48 Array<String> buffer_; 49 bool has_accept_header_; 50}; 51 52void AddRequestBody(URLRequest* url_request, 53 const blink::WebURLRequest& request) { 54 if (request.httpBody().isNull()) 55 return; 56 57 uint32_t i = 0; 58 blink::WebHTTPBody::Element element; 59 while (request.httpBody().elementAt(i++, element)) { 60 switch (element.type) { 61 case blink::WebHTTPBody::Element::TypeData: 62 if (!element.data.isEmpty()) { 63 // WebKit sometimes gives up empty data to append. These aren't 64 // necessary so we just optimize those out here. 65 uint32_t num_bytes = static_cast<uint32_t>(element.data.size()); 66 MojoCreateDataPipeOptions options; 67 options.struct_size = sizeof(MojoCreateDataPipeOptions); 68 options.flags = MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE; 69 options.element_num_bytes = 1; 70 options.capacity_num_bytes = num_bytes; 71 DataPipe data_pipe(options); 72 url_request->body.push_back( 73 data_pipe.consumer_handle.Pass()); 74 WriteDataRaw(data_pipe.producer_handle.get(), 75 element.data.data(), 76 &num_bytes, 77 MOJO_WRITE_DATA_FLAG_ALL_OR_NONE); 78 } 79 break; 80 case blink::WebHTTPBody::Element::TypeFile: 81 case blink::WebHTTPBody::Element::TypeFileSystemURL: 82 case blink::WebHTTPBody::Element::TypeBlob: 83 // TODO(mpcomplete): handle these. 84 NOTIMPLEMENTED(); 85 break; 86 default: 87 NOTREACHED(); 88 } 89 } 90} 91 92} // namespace 93 94URLRequestPtr TypeConverter<URLRequestPtr, blink::WebURLRequest>::Convert( 95 const blink::WebURLRequest& request) { 96 URLRequestPtr url_request(URLRequest::New()); 97 url_request->url = request.url().string().utf8(); 98 url_request->method = request.httpMethod().utf8(); 99 100 HeaderFlattener flattener; 101 request.visitHTTPHeaderFields(&flattener); 102 url_request->headers = flattener.GetBuffer().Pass(); 103 104 AddRequestBody(url_request.get(), request); 105 106 return url_request.Pass(); 107} 108 109} // namespace mojo 110 111