Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

OutOfBlinkCors: M85 POST requests fail with net::ERR_FAILED #3006

Closed
magreenblatt opened this issue Sep 1, 2020 · 20 comments
Closed

OutOfBlinkCors: M85 POST requests fail with net::ERR_FAILED #3006

magreenblatt opened this issue Sep 1, 2020 · 20 comments
Labels
bug Bug report Framework Related to framework code or APIs

Comments

@magreenblatt
Copy link
Collaborator

Original report by Salvador Diaz Fau (Bitbucket: salvadordf, GitHub: salvadordf).


What steps will reproduce the problem?

  1. Run cefclient.
  2. Load https://messages.google.com/web
  3. The QR code will not appear and the DevTools show a net::ERR_FAILED error in the console.

  1. Run cefclient.
  2. Load https://bitbucket.org/
  3. Click on login and type any fake username and password.
  4. It shows an error message “Something went wrong while attempting to validate your credentials.” and the DevTools show a net::ERR_FAILED error in the console.

What is the expected output? What do you see instead?

In the case of Google.com it should show a QR code and with bitbucket.org it should authenticate the user if the useranme and password were real.

What version of the product are you using? On what operating system?

CEF 85.2.11+g0202816+chromium-85.0.4183.83

Windows 10 64 bits

http://opensource.spotify.com/cefbuilds/cef_binary_85.2.11%2Bg0202816%2Bchromium-85.0.4183.83_windows64_client.tar.bz2

Does the problem reproduce with the cefclient or cefsimple sample application at the same version? How about with a newer or older version?

This issue started with CEF 85.2.9. The previous cefclient version (CEF 84.4.1) worked perfectly.

Does the problem reproduce with Google Chrome at the same version? How about with a newer or older version?

Chrome 85 works correctly.

Workaround :

Run cefclient with this switch --disable-features=OutOfBlinkCors

Related forum thread link :

https://magpcss.org/ceforum/viewtopic.php?f=6&t=17826

@magreenblatt
Copy link
Collaborator Author

Original comment by Salvador Diaz Fau (Bitbucket: salvadordf, GitHub: salvadordf).


typo

@magreenblatt
Copy link
Collaborator Author

Original changes by Salvador Diaz Fau (Bitbucket: salvadordf, GitHub: salvadordf).


  • edited description

@magreenblatt
Copy link
Collaborator Author

Thanks for creating this issue.

@magreenblatt
Copy link
Collaborator Author

  • changed title from "Requests fail with net::ERR_FAILED" to "OutOfBlinkCors: M85 POST requests fail with net::ERR_FAILED"

@magreenblatt
Copy link
Collaborator Author

Related forum thread: https://magpcss.org/ceforum/viewtopic.php?f=6&t=17826

@magreenblatt
Copy link
Collaborator Author

  • changed component from "Unclassified" to "Framework"

@magreenblatt
Copy link
Collaborator Author

Original comment by Salvador Diaz Fau (Bitbucket: salvadordf, GitHub: salvadordf).


Added forum thread link

@magreenblatt
Copy link
Collaborator Author

Original changes by Salvador Diaz Fau (Bitbucket: salvadordf, GitHub: salvadordf).


  • edited description

@magreenblatt
Copy link
Collaborator Author

Looking at the net log (created with chrome://net-export) for the Google QR request, with OutOfBlinkCors disabled:

t=2039 [st=0] +REQUEST_ALIVE  [dt=2]
               --> priority = "MEDIUM"
               --> traffic_annotation = [101845102 (bb)](https://bitbucket.org/chromiumembedded/cef/commits/101845102)
               --> url = "https://instantmessaging-pa.googleapis.com/$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay"
t=2040 [st=1]    NETWORK_DELEGATE_BEFORE_URL_REQUEST  [dt=0]
t=2040 [st=1]   +URL_REQUEST_START_JOB  [dt=1]
                 --> initiator = "https://messages.google.com"
                 --> load_flags = 832 (DO_NOT_SAVE_COOKIES | DO_NOT_SEND_AUTH_DATA | DO_NOT_SEND_COOKIES)
                 --> method = "OPTIONS"
                 --> network_isolation_key = "https://google.com https://google.com"
                 --> privacy_mode = "enabled"
                 --> site_for_cookies = "SiteForCookies: {scheme=; registrable_domain=; schemefully_same=false}"
                 --> url = "https://instantmessaging-pa.googleapis.com/$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay"
t=2040 [st=1]      NETWORK_DELEGATE_BEFORE_START_TRANSACTION  [dt=1]
t=2041 [st=2]      CANCELLED
t=2041 [st=2] -REQUEST_ALIVE

And with OutOfBlinkCors enabled:

t=4146 [st=  0] +REQUEST_ALIVE  [dt=301]
                 --> priority = "MEDIUM"
                 --> traffic_annotation = [101845102 (bb)](https://bitbucket.org/chromiumembedded/cef/commits/101845102)
                 --> url = "https://instantmessaging-pa.googleapis.com/$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay"
t=4146 [st=  0]    NETWORK_DELEGATE_BEFORE_URL_REQUEST  [dt=0]
t=4146 [st=  0]   +URL_REQUEST_START_JOB  [dt=300]
                   --> initiator = "https://messages.google.com"
                   --> load_flags = 832 (DO_NOT_SAVE_COOKIES | DO_NOT_SEND_AUTH_DATA | DO_NOT_SEND_COOKIES)
                   --> method = "OPTIONS"
                   --> network_isolation_key = "https://google.com https://google.com"
                   --> privacy_mode = "enabled"
                   --> site_for_cookies = "SiteForCookies: {scheme=https; registrable_domain=google.com; schemefully_same=true}"
                   --> url = "https://instantmessaging-pa.googleapis.com/$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay"
t=4146 [st=  0]      NETWORK_DELEGATE_BEFORE_START_TRANSACTION  [dt=1]
t=4147 [st=  1]      HTTP_CACHE_GET_BACKEND  [dt=0]
t=4148 [st=  2]     +HTTP_STREAM_REQUEST  [dt=170]
t=4148 [st=  2]        HTTP_STREAM_JOB_CONTROLLER_BOUND
                       --> source_dependency = 315 (HTTP_STREAM_JOB_CONTROLLER)
t=4318 [st=172]        HTTP_STREAM_REQUEST_BOUND_TO_JOB
                       --> source_dependency = 316 (HTTP_STREAM_JOB)
t=4318 [st=172]     -HTTP_STREAM_REQUEST
t=4319 [st=173]     +HTTP_TRANSACTION_SEND_REQUEST  [dt=8]
t=4319 [st=173]        HTTP_TRANSACTION_HTTP2_SEND_REQUEST_HEADERS
                       --> :method: OPTIONS
                           :authority: instantmessaging-pa.googleapis.com
                           :scheme: https
                           :path: /$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay
                           access-control-request-method: POST
                           origin: https://messages.google.com
                           user-agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
                           access-control-request-headers: content-type,x-goog-api-key,x-user-agent
                           accept: */*
                           sec-fetch-site: cross-site
                           sec-fetch-mode: cors
                           sec-fetch-dest: empty
                           referer: https://messages.google.com/web/authentication
                           accept-encoding: gzip, deflate, br
                           accept-language: en-US,en;q=0.9
t=4327 [st=181]     -HTTP_TRANSACTION_SEND_REQUEST
t=4327 [st=181]     +HTTP_TRANSACTION_READ_HEADERS  [dt=118]
t=4329 [st=183]        HTTP2_STREAM_UPDATE_SEND_WINDOW
                       --> delta = [983041 (bb)](https://bitbucket.org/chromiumembedded/cef/commits/983041)
                       --> stream_id = 1
                       --> window_size = [1048576 (bb)](https://bitbucket.org/chromiumembedded/cef/commits/1048576)
t=4445 [st=299]        HTTP_TRANSACTION_READ_RESPONSE_HEADERS
                       --> HTTP/1.1 200
                           status: 200
                           access-control-allow-origin: https://messages.google.com
                           vary: origin
                           vary: referer
                           vary: x-origin
                           access-control-allow-credentials: true
                           access-control-allow-methods: DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT
                           access-control-allow-headers: content-type,x-goog-api-key,x-user-agent
                           access-control-max-age: 3600
                           date: Thu, 10 Sep 2020 14:34:16 GMT
                           content-type: text/html
                           server: ESF
                           content-length: 0
                           x-xss-protection: 0
                           x-frame-options: SAMEORIGIN
                           x-content-type-options: nosniff
                           alt-svc: h3-29=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-T050=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
t=4445 [st=299]     -HTTP_TRANSACTION_READ_HEADERS
t=4445 [st=299]      NETWORK_DELEGATE_HEADERS_RECEIVED  [dt=1]
t=4446 [st=300]   -URL_REQUEST_START_JOB
t=4446 [st=300]    URL_REQUEST_DELEGATE_RESPONSE_STARTED  [dt=1]
t=4447 [st=301]    HTTP_TRANSACTION_READ_BODY  [dt=0]
t=4447 [st=301] -REQUEST_ALIVE

@magreenblatt
Copy link
Collaborator Author

The ERR_FAILED is coming from URLLoader::OnMojoDisconnect in the network process, but I’ve so far been unable to identify why Mojo is disconnecting. The request originates from the renderer process with this call stack:

>	blink_core.dll!blink::ThreadableLoader::Start(blink::ResourceRequest request) Line 235	C++
 	blink_core.dll!blink::XMLHttpRequest::CreateRequest(scoped_refptr<blink::EncodedFormData> http_body, blink::ExceptionState & exception_state) Line 1161	C++
 	blink_core.dll!blink::XMLHttpRequest::send(const WTF::String & body, blink::ExceptionState & exception_state) Line 853	C++
 	blink_core.dll!blink::XMLHttpRequest::send(const blink::DocumentOrBlobOrArrayBufferOrArrayBufferViewOrFormDataOrURLSearchParamsOrUSVString & body, blink::ExceptionState & exception_state) Line 805	C++
 	blink_core.dll!blink::xml_http_request_v8_internal::SendMethod(const v8::FunctionCallbackInfo<v8::Value> & info) Line 481	C++
 	blink_core.dll!blink::V8XMLHttpRequest::SendMethodCallback(const v8::FunctionCallbackInfo<v8::Value> & info) Line 715	C++

@magreenblatt
Copy link
Collaborator Author

After ThreadableLoader::Start initiates the “POST” request we get an “OPTIONS” request to URLLoader::URLLoader via this call stack:

>	network_service.dll!network::URLLoader::URLLoader(net::URLRequestContext * url_request_context, network::mojom::NetworkServiceClient * network_service_client, network::mojom::NetworkContextClient * network_context_client, base::OnceCallback<void (network::mojom::URLLoader *)> delete_callback, mojo::PendingReceiver<network::mojom::URLLoader> url_loader_receiver, int options, const network::ResourceRequest & request, mojo::PendingRemote<network::mojom::URLLoaderClient> url_loader_client, base::Optional<network::DataPipeUseTracker> response_body_use_tracker, const net::NetworkTrafficAnnotationTag & traffic_annotation, const network::mojom::URLLoaderFactoryParams * factory_params, network::mojom::CrossOriginEmbedderPolicyReporter * coep_reporter, unsigned int request_id, int keepalive_request_size, scoped_refptr<network::ResourceSchedulerClient> resource_scheduler_client, base::WeakPtr<network::KeepaliveStatisticsRecorder> keepalive_statistics_recorder, base::WeakPtr<network::NetworkUsageAccumulator> network_usage_accumulator, network::mojom::TrustedURLLoaderHeaderClient * url_loader_header_client, network::mojom::OriginPolicyManager * origin_policy_manager, std::__1::unique_ptr<network::TrustTokenRequestHelperFactory,std::__1::default_delete<network::TrustTokenRequestHelperFactory>> trust_token_helper_factory, mojo::PendingRemote<network::mojom::CookieAccessObserver> cookie_observer) Line 520	C++
 	network_service.dll!std::__1::make_unique<network::URLLoader,net::URLRequestContext *,network::mojom::NetworkServiceClient *&,network::mojom::NetworkContextClient *,base::OnceCallback<void (network::mojom::URLLoader *)>,mojo::PendingReceiver<network::mojom::URLLoader>,unsigned int &,const network::ResourceRequest &,mojo::PendingRemote<network::mojom::URLLoaderClient>,base::Optional<network::DataPipeUseTracker>,net::NetworkTrafficAnnotationTag,network::mojom::URLLoaderFactoryParams *,network::mojom::CrossOriginEmbedderPolicyReporterProxy *,int &,int &,scoped_refptr<network::ResourceSchedulerClient> &,base::WeakPtr<network::KeepaliveStatisticsRecorder>,base::WeakPtr<network::NetworkUsageAccumulator>,network::mojom::TrustedURLLoaderHeaderClientProxy *,network::mojom::OriginPolicyManager *,std::__1::unique_ptr<network::TrustTokenRequestHelperFactory,std::__1::default_delete<network::TrustTokenRequestHelperFactory>>,mojo::PendingRemote<network::mojom::CookieAccessObserver>>(net::URLRequestContext * && __args, network::mojom::NetworkServiceClient * & __args, network::mojom::NetworkContextClient * && __args, base::OnceCallback<void (network::mojom::URLLoader *)> && __args, mojo::PendingReceiver<network::mojom::URLLoader> && __args, unsigned int & __args, const network::ResourceRequest & __args, mojo::PendingRemote<network::mojom::URLLoaderClient> && __args, base::Optional<network::DataPipeUseTracker> && __args, net::NetworkTrafficAnnotationTag && __args, network::mojom::URLLoaderFactoryParams * && __args, network::mojom::CrossOriginEmbedderPolicyReporterProxy * && __args, int & __args, int & __args, scoped_refptr<network::ResourceSchedulerClient> & __args, base::WeakPtr<network::KeepaliveStatisticsRecorder> && __args, base::WeakPtr<network::NetworkUsageAccumulator> && __args, network::mojom::TrustedURLLoaderHeaderClientProxy * && __args, network::mojom::OriginPolicyManager * && __args, std::__1::unique_ptr<network::TrustTokenRequestHelperFactory,std::__1::default_delete<network::TrustTokenRequestHelperFactory>> && __args, mojo::PendingRemote<network::mojom::CookieAccessObserver> && __args) Line 3043	C++
 	network_service.dll!network::URLLoaderFactory::CreateLoaderAndStart(mojo::PendingReceiver<network::mojom::URLLoader> receiver, int routing_id, int request_id, unsigned int options, const network::ResourceRequest & url_request, mojo::PendingRemote<network::mojom::URLLoaderClient> client, const net::MutableNetworkTrafficAnnotationTag & traffic_annotation) Line 260	C++
 	network_cpp.dll!network::`anonymous namespace'::SimpleURLLoaderImpl::StartRequest(network::mojom::URLLoaderFactory * url_loader_factory) Line 1526	C++
 	network_cpp.dll!network::`anonymous namespace'::SimpleURLLoaderImpl::Start(network::mojom::URLLoaderFactory * url_loader_factory) Line 1508	C++
 	network_cpp.dll!network::`anonymous namespace'::SimpleURLLoaderImpl::DownloadToString(network::mojom::URLLoaderFactory * url_loader_factory, base::OnceCallback<void (std::__1::unique_ptr<std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>,std::__1::default_delete<std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>>>)> body_as_string_callback, unsigned int max_body_size) Line 1187	C++
 	network_service.dll!network::cors::PreflightController::PreflightLoader::Request(network::mojom::URLLoaderFactory * loader_factory) Line 241	C++
 	network_service.dll!network::cors::PreflightController::PerformPreflightCheck(base::OnceCallback<void (int, base::Optional<network::CorsErrorStatus>)> callback, const network::ResourceRequest & request, util::StrongAlias<network::cors::WithTrustedHeaderClientTag,bool> with_trusted_header_client, bool tainted, const net::NetworkTrafficAnnotationTag & annotation_tag, network::mojom::URLLoaderFactory * loader_factory, int process_id, const net::IsolationInfo & isolation_info) Line 427	C++
 	network_service.dll!network::cors::CorsURLLoader::StartRequest() Line 524	C++
 	network_service.dll!network::cors::CorsURLLoader::Start() Line 153	C++
 	network_service.dll!network::cors::CorsURLLoaderFactory::CreateLoaderAndStart(mojo::PendingReceiver<network::mojom::URLLoader> receiver, int routing_id, int request_id, unsigned int options, const network::ResourceRequest & resource_request, mojo::PendingRemote<network::mojom::URLLoaderClient> client, const net::MutableNetworkTrafficAnnotationTag & traffic_annotation) Line 267	C++

That results in a call to PreflightController::HandleResponseBody which represents a failure with ERR_FAILED, and the request is then marked as complete in CorsURLLoader::StartNetworkRequest.

In other words, the “OPTIONS” request via PreflightController is failing so the “POST” request is never actually sent over the network.

@magreenblatt
Copy link
Collaborator Author

With OutOfBlinkCors disabled the “OPTIONS” request that arrives in URLLoader::URLLoader comes from Blink with this value:

-		request	{method=0x3970dc48 "OPTIONS" url=0x38cf5370 "https://instantmessaging-pa.googleapis.com/$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay" ...}	const network::ResourceRequest &
+		method	0x3970dc48 "OPTIONS"	std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>
+		url	0x38cf5370 "https://instantmessaging-pa.googleapis.com/$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay"	GURL
+		site_for_cookies	{scheme_=0x3970dcb0 "https" registrable_domain_=0x3970dcbc "google.com" schemefully_same_=true }	net::SiteForCookies
		force_ignore_site_for_cookies	false	bool
		update_first_party_url_on_redirect	false	bool
+		request_initiator	{tuple_={scheme_=0x3970dcd8 "https" host_=0x38f7c5a0 "messages.google.com" port_=443 } nonce_=(null) }	base::Optional<url::Origin>
+		isolated_world_origin	(null)	base::Optional<url::Origin>
+		referrer	0x38f99390 "https://messages.google.com/web/authentication"	GURL
		referrer_policy	CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE (0)	net::URLRequest::ReferrerPolicy
-		headers	{headers_={ size=5 } }	net::HttpRequestHeaders
-		headers_	{ size=5 }	std::__1::vector<net::HttpRequestHeaders::HeaderKeyValuePair,std::__1::allocator<net::HttpRequestHeaders::HeaderKeyValuePair>>
+		[0]	{key=0x38f7c500 "Access-Control-Request-Method" value=0x38e531e4 "POST" }	net::HttpRequestHeaders::HeaderKeyValuePair
+		[1]	{key=0x38e531f0 "Origin" value=0x38f7c2d0 "https://messages.google.com" }	net::HttpRequestHeaders::HeaderKeyValuePair
+		[2]	{key=0x38e53208 "User-Agent" value=0x011ab7f0 "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36" }	net::HttpRequestHeaders::HeaderKeyValuePair
+		[3]	{key=0x38f7bf10 "Access-Control-Request-Headers" value=0x38f87830 "content-type,x-goog-api-key,x-user-agent" }	net::HttpRequestHeaders::HeaderKeyValuePair
+		[4]	{key=0x38e53238 "Accept" value=0x38e53244 "*/*" }	net::HttpRequestHeaders::HeaderKeyValuePair
+		[Raw View]	{...}	std::__1::vector<net::HttpRequestHeaders::HeaderKeyValuePair,std::__1::allocator<net::HttpRequestHeaders::HeaderKeyValuePair>>
+		cors_exempt_headers	{headers_={ size=0 } }	net::HttpRequestHeaders
		load_flags	832	int
		resource_type	13	int
		priority	MEDIUM (4)	net::RequestPriority
		should_reset_appcache	false	bool
		is_external_request	false	bool
		cors_preflight_policy	kConsiderPreflight (0)	network::mojom::CorsPreflightPolicy
		originated_from_service_worker	false	bool
		skip_service_worker	true	bool
		corb_detachable	false	bool
		corb_excluded	false	bool
		mode	kCors (2)	network::mojom::RequestMode
		credentials_mode	kOmit (0)	network::mojom::CredentialsMode
		redirect_mode	kFollow (0)	network::mojom::RedirectMode
+		fetch_integrity	0x3970ddec ""	std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>
		destination	kEmpty (0)	network::mojom::RequestDestination
+		request_body	null	scoped_refptr<network::ResourceRequestBody>
		keepalive	false	bool
		has_user_gesture	false	bool
		enable_load_timing	true	bool
		enable_upload_progress	false	bool
		do_not_prompt_for_login	false	bool
		render_frame_id	1	int
		is_main_frame	true	bool
		transition_type	0	int
		report_raw_headers	false	bool
		previews_state	32	int
		upgrade_if_insecure	false	bool
		is_revalidating	false	bool
+		throttling_profile_id	(null)	base::Optional<base::UnguessableToken>
+		custom_proxy_pre_cache_headers	{headers_={ size=0 } }	net::HttpRequestHeaders
+		custom_proxy_post_cache_headers	{headers_={ size=0 } }	net::HttpRequestHeaders
+		fetch_window_id	{token_={high_=9580157559802765761 low_=10215553856384420913 } }	base::Optional<base::UnguessableToken>
+		devtools_request_id	(null)	base::Optional<std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>>
		is_signed_exchange_prefetch_cache_enabled	false	bool
		obey_origin_policy	false	bool
+		recursive_prefetch_token	(null)	base::Optional<base::UnguessableToken>
+		trusted_params	(null)	base::Optional<network::ResourceRequest::TrustedParams>
+		trust_token_params	{ptr_={ptr_=empty } }	network::OptionalTrustTokenParams

With OutOfBlinkCors enabled the “OPTIONS” request arrives from PreflightController with this value:

-		request	{method=0x387b0480 "OPTIONS" url=0x007ca478 "https://instantmessaging-pa.googleapis.com/$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay" ...}	const network::ResourceRequest &
+		method	0x387b0480 "OPTIONS"	std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>
+		url	0x007ca478 "https://instantmessaging-pa.googleapis.com/$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay"	GURL
+		site_for_cookies	{scheme_=0x387b04e8 "" registrable_domain_=0x387b04f4 "" schemefully_same_=false }	net::SiteForCookies
		force_ignore_site_for_cookies	false	bool
		update_first_party_url_on_redirect	false	bool
+		request_initiator	{tuple_={scheme_=0x387b0510 "https" host_=0x3878b0b8 "messages.google.com" port_=443 } nonce_=(null) }	base::Optional<url::Origin>
+		isolated_world_origin	(null)	base::Optional<url::Origin>
+		referrer	0x3878bdf8 "https://messages.google.com/web/authentication"	GURL
		referrer_policy	CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE (0)	net::URLRequest::ReferrerPolicy
-		headers	{headers_={ size=5 } }	net::HttpRequestHeaders
-		headers_	{ size=5 }	std::__1::vector<net::HttpRequestHeaders::HeaderKeyValuePair,std::__1::allocator<net::HttpRequestHeaders::HeaderKeyValuePair>>
+		[0]	{key=0x38697ce8 "Accept" value=0x38697cf4 "*/*" }	net::HttpRequestHeaders::HeaderKeyValuePair
+		[1]	{key=0x3878af78 "Access-Control-Request-Method" value=0x38697d0c "POST" }	net::HttpRequestHeaders::HeaderKeyValuePair
+		[2]	{key=0x3878ab68 "Access-Control-Request-Headers" value=0x3878c278 "content-type,x-goog-api-key,x-user-agent" }	net::HttpRequestHeaders::HeaderKeyValuePair
+		[3]	{key=0x38697d30 "Origin" value=0x3878abb8 "https://messages.google.com" }	net::HttpRequestHeaders::HeaderKeyValuePair
+		[4]	{key=0x386781b0 "Sec-Fetch-Mode" value=0x38697d54 "cors" }	net::HttpRequestHeaders::HeaderKeyValuePair
+		[Raw View]	{...}	std::__1::vector<net::HttpRequestHeaders::HeaderKeyValuePair,std::__1::allocator<net::HttpRequestHeaders::HeaderKeyValuePair>>
+		cors_exempt_headers	{headers_={ size=0 } }	net::HttpRequestHeaders
		load_flags	0	int
		resource_type	13	int
		priority	MEDIUM (4)	net::RequestPriority
		should_reset_appcache	false	bool
		is_external_request	false	bool
		cors_preflight_policy	kConsiderPreflight (0)	network::mojom::CorsPreflightPolicy
		originated_from_service_worker	false	bool
		skip_service_worker	false	bool
		corb_detachable	false	bool
		corb_excluded	false	bool
		mode	kNoCors (1)	network::mojom::RequestMode
		credentials_mode	kOmit (0)	network::mojom::CredentialsMode
		redirect_mode	kFollow (0)	network::mojom::RedirectMode
+		fetch_integrity	0x387b0624 ""	std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>
		destination	kEmpty (0)	network::mojom::RequestDestination
+		request_body	null	scoped_refptr<network::ResourceRequestBody>
		keepalive	false	bool
		has_user_gesture	false	bool
		enable_load_timing	false	bool
		enable_upload_progress	false	bool
		do_not_prompt_for_login	false	bool
		render_frame_id	1	int
		is_main_frame	false	bool
		transition_type	0	int
		report_raw_headers	false	bool
		previews_state	0	int
		upgrade_if_insecure	false	bool
		is_revalidating	false	bool
+		throttling_profile_id	(null)	base::Optional<base::UnguessableToken>
+		custom_proxy_pre_cache_headers	{headers_={ size=0 } }	net::HttpRequestHeaders
+		custom_proxy_post_cache_headers	{headers_={ size=0 } }	net::HttpRequestHeaders
+		fetch_window_id	(null)	base::Optional<base::UnguessableToken>
+		devtools_request_id	(null)	base::Optional<std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>>
		is_signed_exchange_prefetch_cache_enabled	false	bool
		obey_origin_policy	false	bool
+		recursive_prefetch_token	(null)	base::Optional<base::UnguessableToken>
+		trusted_params	(null)	base::Optional<network::ResourceRequest::TrustedParams>
+		trust_token_params	{ptr_={ptr_=empty } }	network::OptionalTrustTokenParams

@magreenblatt
Copy link
Collaborator Author

With memory addresses removed the diff between the two results is:

diff --git in_blink.txt out_blink.txt
index [51c18ab (bb)](https://bitbucket.org/chromiumembedded/cef/commits/51c18ab)..b689726 [100644 (bb)](https://bitbucket.org/chromiumembedded/cef/commits/100644)
--- in_blink.txt
+++ out_blink.txt
@@ -1,7 +1,7 @@
 -       request {method= "OPTIONS" url= "https://instantmessaging-pa.googleapis.com/$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay" ...}    const network::ResourceRequest &
 +       method   "OPTIONS"    std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>
 +       url  "https://instantmessaging-pa.googleapis.com/$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay"  GURL
-+       site_for_cookies    {scheme_= "https" registrable_domain_= "google.com" schemefully_same_=true }    net::SiteForCookies
++       site_for_cookies    {scheme_= "" registrable_domain_= "" schemefully_same_=false }  net::SiteForCookies
         force_ignore_site_for_cookies   false   bool
         update_first_party_url_on_redirect  false   bool
 +       request_initiator   {tuple_={scheme_= "https" host_= "messages.google.com" port_=443 } nonce_=(null) }  base::Optional<url::Origin>
@@ -10,24 +10,24 @@
         referrer_policy CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE (0)    net::URLRequest::ReferrerPolicy
 -       headers {headers_={ size=5 } }  net::HttpRequestHeaders
 -       headers_    { size=5 }  std::__1::vector<net::HttpRequestHeaders::HeaderKeyValuePair,std::__1::allocator<net::HttpRequestHeaders::HeaderKeyValuePair>>
-+       [0] {key= "Access-Control-Request-Method" value= "POST" }   net::HttpRequestHeaders::HeaderKeyValuePair
-+       [1] {key= "Origin" value= "https://messages.google.com" }   net::HttpRequestHeaders::HeaderKeyValuePair
-+       [2] {key= "User-Agent" value="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36" }    net::HttpRequestHeaders::HeaderKeyValuePair
-+       [3] {key= "Access-Control-Request-Headers" value= "content-type,x-goog-api-key,x-user-agent" }  net::HttpRequestHeaders::HeaderKeyValuePair
-+       [4] {key= "Accept" value= "*/*" }   net::HttpRequestHeaders::HeaderKeyValuePair
++       [0] {key= "Accept" value= "*/*" }   net::HttpRequestHeaders::HeaderKeyValuePair
++       [1] {key= "Access-Control-Request-Method" value= "POST" }   net::HttpRequestHeaders::HeaderKeyValuePair
++       [2] {key= "Access-Control-Request-Headers" value= "content-type,x-goog-api-key,x-user-agent" }  net::HttpRequestHeaders::HeaderKeyValuePair
++       [3] {key= "Origin" value= "https://messages.google.com" }   net::HttpRequestHeaders::HeaderKeyValuePair
++       [4] {key= "Sec-Fetch-Mode" value= "cors" }  net::HttpRequestHeaders::HeaderKeyValuePair
 +       [Raw View]  {...}   std::__1::vector<net::HttpRequestHeaders::HeaderKeyValuePair,std::__1::allocator<net::HttpRequestHeaders::HeaderKeyValuePair>>
 +       cors_exempt_headers {headers_={ size=0 } }  net::HttpRequestHeaders
-        load_flags  832 int
+        load_flags  0   int
         resource_type   13  int
         priority    MEDIUM (4)  net::RequestPriority
         should_reset_appcache   false   bool
         is_external_request false   bool
         cors_preflight_policy   kConsiderPreflight (0)  network::mojom::CorsPreflightPolicy
         originated_from_service_worker  false   bool
-        skip_service_worker true    bool
+        skip_service_worker false   bool
         corb_detachable false   bool
         corb_excluded   false   bool
-        mode    kCors (2)   network::mojom::RequestMode
+        mode    kNoCors (1) network::mojom::RequestMode
         credentials_mode    kOmit (0)   network::mojom::CredentialsMode
         redirect_mode   kFollow (0) network::mojom::RedirectMode
 +       fetch_integrity  ""   std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>
@@ -35,20 +35,20 @@
 +       request_body    null    scoped_refptr<network::ResourceRequestBody>
         keepalive   false   bool
         has_user_gesture    false   bool
-        enable_load_timing  true    bool
+        enable_load_timing  false   bool
         enable_upload_progress  false   bool
         do_not_prompt_for_login false   bool
         render_frame_id 1   int
-        is_main_frame   true    bool
+        is_main_frame   false   bool
         transition_type 0   int
         report_raw_headers  false   bool
-        previews_state  32  int
+        previews_state  0   int
         upgrade_if_insecure false   bool
         is_revalidating false   bool
 +       throttling_profile_id   (null)  base::Optional<base::UnguessableToken>
 +       custom_proxy_pre_cache_headers  {headers_={ size=0 } }  net::HttpRequestHeaders
 +       custom_proxy_post_cache_headers {headers_={ size=0 } }  net::HttpRequestHeaders
-+       fetch_window_id {token_={high_= low_= } }    base::Optional<base::UnguessableToken>
++       fetch_window_id (null)  base::Optional<base::UnguessableToken>
 +       devtools_request_id (null)  base::Optional<std::__1::basic_string<char,std::__1::char_traits<char>,std::__1::allocator<char>>>
         is_signed_exchange_prefetch_cache_enabled   false   bool
         obey_origin_policy  false   bool

The most important one might be the missing "User-Agent" header with OutOfBlinkCors enabled.

@magreenblatt
Copy link
Collaborator Author

Missing "User-Agent" doesn’t appear to be the problem as the request works with curl:

$ curl -v -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: content-type,x-goog-api-key,x-user-agent" -H "Accept: */*" -H "Origin: https://messages.google.com" -H "User-Agent:" -X OPTIONS https://instantmessaging-pa.googleapis.com/\$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay
* Connected to instantmessaging-pa.googleapis.com (2607:f8b0:4009:80f::200a) port 443 (#0)
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* Connection state changed (HTTP/2 confirmed)
> OPTIONS /$rpc/google.internal.communications.instantmessaging.v1.Pairing/RegisterPhoneRelay HTTP/2
> Host: instantmessaging-pa.googleapis.com
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: content-type,x-goog-api-key,x-user-agent
> Accept: */*
> Origin: https://messages.google.com
>
< HTTP/2 200
< access-control-allow-origin: https://messages.google.com
< vary: origin
< vary: referer
< vary: x-origin
< access-control-allow-credentials: true
< access-control-allow-methods: DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT
< access-control-allow-headers: content-type,x-goog-api-key,x-user-agent
< access-control-max-age: 3600
< date: Thu, 10 Sep 2020 19:04:04 GMT
< content-type: text/html
< server: ESF
< content-length: 0
< x-xss-protection: 0
< x-frame-options: SAMEORIGIN
< x-content-type-options: nosniff
< alt-svc: h3-29=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-T050=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"

@magreenblatt
Copy link
Collaborator Author

ProxyURLLoaderFactory::CreateLoaderAndStart and InterceptedRequest::ContinueAfterIntercept see the “POST” request but not the “OPTIONS” request. Bypassing ProxyURLLoaderFactory by setting |pass_through| to true in ProxyURLLoaderFactory::CreateLoaderAndStart causes the request to succeed.

@magreenblatt
Copy link
Collaborator Author

Well, duh. The “OPTIONS” request arrives in ProxyURLLoaderFactory::OnLoaderForCorsPreflightCreated which is not currently implemented.

@magreenblatt
Copy link
Collaborator Author

Support CORS preflight requests with OutOfBlinkCors (fixes issue #3006)

A CORS preflight request is an "OPTIONS" request sent to a server prior to a
cross-origin XMLHttpRequest or Fetch request. The server's response determines
which HTTP request methods are allowed and supported, and whether credentials
such as Cookies and HTTP Authentication should be sent with requests.

A CORS preflight request will only be sent if certain conditions are met. For
example, it will be sent for requests that have potentially unsafe HTTP
methods [1] or request headers [2]. See the NeedsPreflight function in
services/network/cors/cors_url_loader.cc for full details.

CORS preflight functionality is implemented in the network service and will not
be triggered if the client handles the request instead of allowing it to proceed
over the network. Since the preflight request itself also runs in the network
service it cannot be intercepted by the client.

[1] https://fetch.spec.whatwg.org/#cors-safelisted-method
[2] https://fetch.spec.whatwg.org/#cors-safelisted-request-header

→ <<cset acfac2f56b3b (bb)>>

@magreenblatt
Copy link
Collaborator Author

  • changed state from "new" to "resolved"

@magreenblatt
Copy link
Collaborator Author

Support CORS preflight requests with OutOfBlinkCors (fixes issue #3006)

A CORS preflight request is an "OPTIONS" request sent to a server prior to a
cross-origin XMLHttpRequest or Fetch request. The server's response determines
which HTTP request methods are allowed and supported, and whether credentials
such as Cookies and HTTP Authentication should be sent with requests.

A CORS preflight request will only be sent if certain conditions are met. For
example, it will be sent for requests that have potentially unsafe HTTP
methods [1] or request headers [2]. See the NeedsPreflight function in
services/network/cors/cors_url_loader.cc for full details.

CORS preflight functionality is implemented in the network service and will not
be triggered if the client handles the request instead of allowing it to proceed
over the network. Since the preflight request itself also runs in the network
service it cannot be intercepted by the client.

[1] https://fetch.spec.whatwg.org/#cors-safelisted-method
[2] https://fetch.spec.whatwg.org/#cors-safelisted-request-header

→ <<cset 4cfacc47431a (bb)>>

@magreenblatt
Copy link
Collaborator Author

Support CORS preflight requests with OutOfBlinkCors (fixes issue #3006)

A CORS preflight request is an "OPTIONS" request sent to a server prior to a
cross-origin XMLHttpRequest or Fetch request. The server's response determines
which HTTP request methods are allowed and supported, and whether credentials
such as Cookies and HTTP Authentication should be sent with requests.

A CORS preflight request will only be sent if certain conditions are met. For
example, it will be sent for requests that have potentially unsafe HTTP
methods [1] or request headers [2]. See the NeedsPreflight function in
services/network/cors/cors_url_loader.cc for full details.

CORS preflight functionality is implemented in the network service and will not
be triggered if the client handles the request instead of allowing it to proceed
over the network. Since the preflight request itself also runs in the network
service it cannot be intercepted by the client.

[1] https://fetch.spec.whatwg.org/#cors-safelisted-method
[2] https://fetch.spec.whatwg.org/#cors-safelisted-request-header

→ <<cset cc56720bd29a (bb)>>

S1artie pushed a commit to GEBIT/cef that referenced this issue Aug 10, 2023
…miumembedded#3006)

A CORS preflight request is an "OPTIONS" request sent to a server prior to a
cross-origin XMLHttpRequest or Fetch request. The server's response determines
which HTTP request methods are allowed and supported, and whether credentials
such as Cookies and HTTP Authentication should be sent with requests.

A CORS preflight request will only be sent if certain conditions are met. For
example, it will be sent for requests that have potentially unsafe HTTP
methods [1] or request headers [2]. See the NeedsPreflight function in
services/network/cors/cors_url_loader.cc for full details.

CORS preflight functionality is implemented in the network service and will not
be triggered if the client handles the request instead of allowing it to proceed
over the network. Since the preflight request itself also runs in the network
service it cannot be intercepted by the client.

[1] https://fetch.spec.whatwg.org/#cors-safelisted-method
[2] https://fetch.spec.whatwg.org/#cors-safelisted-request-header
filipnavara pushed a commit to emclient/cef that referenced this issue Dec 26, 2023
…miumembedded#3006)

A CORS preflight request is an "OPTIONS" request sent to a server prior to a
cross-origin XMLHttpRequest or Fetch request. The server's response determines
which HTTP request methods are allowed and supported, and whether credentials
such as Cookies and HTTP Authentication should be sent with requests.

A CORS preflight request will only be sent if certain conditions are met. For
example, it will be sent for requests that have potentially unsafe HTTP
methods [1] or request headers [2]. See the NeedsPreflight function in
services/network/cors/cors_url_loader.cc for full details.

CORS preflight functionality is implemented in the network service and will not
be triggered if the client handles the request instead of allowing it to proceed
over the network. Since the preflight request itself also runs in the network
service it cannot be intercepted by the client.

[1] https://fetch.spec.whatwg.org/#cors-safelisted-method
[2] https://fetch.spec.whatwg.org/#cors-safelisted-request-header
filipnavara pushed a commit to emclient/cef that referenced this issue Dec 26, 2023
…miumembedded#3006)

A CORS preflight request is an "OPTIONS" request sent to a server prior to a
cross-origin XMLHttpRequest or Fetch request. The server's response determines
which HTTP request methods are allowed and supported, and whether credentials
such as Cookies and HTTP Authentication should be sent with requests.

A CORS preflight request will only be sent if certain conditions are met. For
example, it will be sent for requests that have potentially unsafe HTTP
methods [1] or request headers [2]. See the NeedsPreflight function in
services/network/cors/cors_url_loader.cc for full details.

CORS preflight functionality is implemented in the network service and will not
be triggered if the client handles the request instead of allowing it to proceed
over the network. Since the preflight request itself also runs in the network
service it cannot be intercepted by the client.

[1] https://fetch.spec.whatwg.org/#cors-safelisted-method
[2] https://fetch.spec.whatwg.org/#cors-safelisted-request-header
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Bug report Framework Related to framework code or APIs
Projects
None yet
Development

No branches or pull requests

1 participant