mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			232 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (c) 2019 The Chromium Embedded Framework Authors. Portions
 | |
| // Copyright (c) 2018 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 "libcef/common/net_service/net_service_util.h"
 | |
| 
 | |
| #include "libcef/common/time_util.h"
 | |
| 
 | |
| #include <set>
 | |
| 
 | |
| #include "base/logging.h"
 | |
| #include "base/strings/string_number_conversions.h"
 | |
| #include "net/cookies/canonical_cookie.h"
 | |
| #include "net/cookies/cookie_util.h"
 | |
| #include "net/cookies/parsed_cookie.h"
 | |
| #include "net/http/http_request_headers.h"
 | |
| #include "net/http/http_response_headers.h"
 | |
| #include "net/http/http_status_code.h"
 | |
| #include "net/url_request/redirect_info.h"
 | |
| #include "net/url_request/redirect_util.h"
 | |
| #include "net/url_request/url_request.h"
 | |
| #include "services/network/public/cpp/resource_request.h"
 | |
| #include "services/network/public/cpp/resource_response.h"
 | |
| 
 | |
| namespace net_service {
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| // Determine the cookie domain to use for setting the specified cookie.
 | |
| // From net/cookies/cookie_store.cc.
 | |
| bool GetCookieDomain(const GURL& url,
 | |
|                      const net::ParsedCookie& pc,
 | |
|                      std::string* result) {
 | |
|   std::string domain_string;
 | |
|   if (pc.HasDomain())
 | |
|     domain_string = pc.Domain();
 | |
|   return net::cookie_util::GetCookieDomainWithString(url, domain_string,
 | |
|                                                      result);
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| const char kHTTPLocationHeaderName[] = "Location";
 | |
| const char kHTTPSetCookieHeaderName[] = "Set-Cookie";
 | |
| 
 | |
| const char kContentTypeApplicationFormURLEncoded[] =
 | |
|     "application/x-www-form-urlencoded";
 | |
| 
 | |
| const char kHTTPHeaderSep[] = ": ";
 | |
| 
 | |
| std::string MakeHeader(const std::string& name, const std::string& value) {
 | |
|   std::string header(name);
 | |
|   header.append(kHTTPHeaderSep);
 | |
|   header.append(value);
 | |
|   return header;
 | |
| }
 | |
| 
 | |
| std::string MakeStatusLine(int status_code,
 | |
|                            const std::string& status_text,
 | |
|                            bool for_replacement) {
 | |
|   std::string status("HTTP/1.1 ");
 | |
|   status.append(base::NumberToString(status_code));
 | |
|   status.append(" ");
 | |
| 
 | |
|   if (status_text.empty()) {
 | |
|     const std::string& text =
 | |
|         net::GetHttpReasonPhrase(static_cast<net::HttpStatusCode>(status_code));
 | |
|     DCHECK(!text.empty());
 | |
|     status.append(text);
 | |
|   } else {
 | |
|     status.append(status_text);
 | |
|   }
 | |
| 
 | |
|   if (!for_replacement) {
 | |
|     // The HttpResponseHeaders constructor expects its input string to be
 | |
|     // terminated by two NULs.
 | |
|     status.append("\0\0", 2);
 | |
|   }
 | |
|   return status;
 | |
| }
 | |
| 
 | |
| std::string MakeContentTypeValue(const std::string& mime_type,
 | |
|                                  const std::string& charset) {
 | |
|   DCHECK(!mime_type.empty());
 | |
|   std::string value = mime_type;
 | |
|   if (!charset.empty()) {
 | |
|     value.append("; charset=");
 | |
|     value.append(charset);
 | |
|   }
 | |
|   return value;
 | |
| }
 | |
| 
 | |
| net::HttpResponseHeaders* MakeResponseHeaders(
 | |
|     int status_code,
 | |
|     const std::string& status_text,
 | |
|     const std::string& mime_type,
 | |
|     const std::string& charset,
 | |
|     int64_t content_length,
 | |
|     const std::multimap<std::string, std::string>& extra_headers,
 | |
|     bool allow_existing_header_override) {
 | |
|   if (status_code <= 0)
 | |
|     status_code = 200;
 | |
| 
 | |
|   auto headers = new net::HttpResponseHeaders(
 | |
|       MakeStatusLine(status_code, status_text, false));
 | |
| 
 | |
|   // Track the headers that have already been set. Perform all comparisons in
 | |
|   // lowercase.
 | |
|   std::set<std::string> set_headers_lowercase;
 | |
| 
 | |
|   if (status_code == net::HTTP_OK) {
 | |
|     if (!mime_type.empty()) {
 | |
|       headers->AddHeader(MakeHeader(net::HttpRequestHeaders::kContentType,
 | |
|                                     MakeContentTypeValue(mime_type, charset)));
 | |
|       set_headers_lowercase.insert(
 | |
|           base::ToLowerASCII(net::HttpRequestHeaders::kContentType));
 | |
|     }
 | |
| 
 | |
|     if (content_length >= 0) {
 | |
|       headers->AddHeader(MakeHeader(net::HttpRequestHeaders::kContentLength,
 | |
|                                     base::NumberToString(content_length)));
 | |
|       set_headers_lowercase.insert(
 | |
|           base::ToLowerASCII(net::HttpRequestHeaders::kContentLength));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (const auto& pair : extra_headers) {
 | |
|     if (!set_headers_lowercase.empty()) {
 | |
|       // Check if the header has already been set.
 | |
|       const std::string& name_lowercase = base::ToLowerASCII(pair.first);
 | |
|       if (set_headers_lowercase.find(name_lowercase) !=
 | |
|           set_headers_lowercase.end()) {
 | |
|         if (allow_existing_header_override)
 | |
|           headers->RemoveHeader(pair.first);
 | |
|         else
 | |
|           continue;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     headers->AddHeader(MakeHeader(pair.first, pair.second));
 | |
|   }
 | |
| 
 | |
|   return headers;
 | |
| }
 | |
| 
 | |
| net::RedirectInfo MakeRedirectInfo(const network::ResourceRequest& request,
 | |
|                                    const net::HttpResponseHeaders* headers,
 | |
|                                    const GURL& new_location,
 | |
|                                    int status_code) {
 | |
|   bool insecure_scheme_was_upgraded = false;
 | |
| 
 | |
|   GURL location = new_location;
 | |
|   if (status_code == 0)
 | |
|     status_code = net::HTTP_TEMPORARY_REDIRECT;
 | |
| 
 | |
|   // If this a redirect to HTTP of a request that had the
 | |
|   // 'upgrade-insecure-requests' policy set, upgrade it to HTTPS.
 | |
|   if (request.upgrade_if_insecure) {
 | |
|     if (location.SchemeIs("http")) {
 | |
|       insecure_scheme_was_upgraded = true;
 | |
|       GURL::Replacements replacements;
 | |
|       replacements.SetSchemeStr("https");
 | |
|       location = location.ReplaceComponents(replacements);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   net::URLRequest::FirstPartyURLPolicy first_party_url_policy =
 | |
|       request.update_first_party_url_on_redirect
 | |
|           ? net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT
 | |
|           : net::URLRequest::NEVER_CHANGE_FIRST_PARTY_URL;
 | |
|   return net::RedirectInfo::ComputeRedirectInfo(
 | |
|       request.method, request.url, request.site_for_cookies,
 | |
|       first_party_url_policy, request.referrer_policy,
 | |
|       request.referrer.spec(), status_code, location,
 | |
|       net::RedirectUtil::GetReferrerPolicyHeader(headers),
 | |
|       insecure_scheme_was_upgraded);
 | |
| }
 | |
| 
 | |
| bool MakeCefCookie(const net::CanonicalCookie& cc, CefCookie& cookie) {
 | |
|   CefString(&cookie.name).FromString(cc.Name());
 | |
|   CefString(&cookie.value).FromString(cc.Value());
 | |
|   CefString(&cookie.domain).FromString(cc.Domain());
 | |
|   CefString(&cookie.path).FromString(cc.Path());
 | |
|   cookie.secure = cc.IsSecure();
 | |
|   cookie.httponly = cc.IsHttpOnly();
 | |
|   cef_time_from_basetime(cc.CreationDate(), cookie.creation);
 | |
|   cef_time_from_basetime(cc.LastAccessDate(), cookie.last_access);
 | |
|   cookie.has_expires = cc.IsPersistent();
 | |
|   if (cookie.has_expires)
 | |
|     cef_time_from_basetime(cc.ExpiryDate(), cookie.expires);
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool MakeCefCookie(const GURL& url,
 | |
|                    const std::string& cookie_line,
 | |
|                    CefCookie& cookie) {
 | |
|   // Parse the cookie.
 | |
|   net::ParsedCookie pc(cookie_line);
 | |
|   if (!pc.IsValid())
 | |
|     return false;
 | |
| 
 | |
|   std::string cookie_domain;
 | |
|   if (!GetCookieDomain(url, pc, &cookie_domain))
 | |
|     return false;
 | |
| 
 | |
|   std::string path_string;
 | |
|   if (pc.HasPath())
 | |
|     path_string = pc.Path();
 | |
|   std::string cookie_path =
 | |
|       net::CanonicalCookie::CanonPathWithString(url, path_string);
 | |
|   base::Time creation_time = base::Time::Now();
 | |
|   base::Time cookie_expires =
 | |
|       net::CanonicalCookie::CanonExpiration(pc, creation_time, creation_time);
 | |
| 
 | |
|   CefString(&cookie.name).FromString(pc.Name());
 | |
|   CefString(&cookie.value).FromString(pc.Value());
 | |
|   CefString(&cookie.domain).FromString(cookie_domain);
 | |
|   CefString(&cookie.path).FromString(cookie_path);
 | |
|   cookie.secure = pc.IsSecure();
 | |
|   cookie.httponly = pc.IsHttpOnly();
 | |
|   cef_time_from_basetime(creation_time, cookie.creation);
 | |
|   cef_time_from_basetime(creation_time, cookie.last_access);
 | |
|   cookie.has_expires = !cookie_expires.is_null();
 | |
|   if (cookie.has_expires)
 | |
|     cef_time_from_basetime(cookie_expires, cookie.expires);
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| }  // namespace net_service
 |