mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	Allow custom schemes to cause redirects (issue #98).
git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@223 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
		| @@ -808,11 +808,12 @@ public: | ||||
|   // Called on the IO thread before a resource is loaded.  To allow the resource | ||||
|   // to load normally return RV_CONTINUE. To redirect the resource to a new url | ||||
|   // populate the |redirectUrl| value and return RV_CONTINUE.  To specify data | ||||
|   // for the resource return a CefStream object in |resourceStream|, set | ||||
|   // |mimeType| to the resource stream's mime type, and return RV_CONTINUE. To | ||||
|   // cancel loading of the resource return RV_HANDLED. Any modifications to | ||||
|   // |request| will be observed.  If the URL in |request| is changed and | ||||
|   // |redirectUrl| is also set, the URL in |request| will be used. | ||||
|   // for the resource return a CefStream object in |resourceStream|, use the | ||||
|   // |response| object to set mime type, HTTP status code and optional header | ||||
|   // values, and return RV_CONTINUE. To cancel loading of the resource return | ||||
|   // RV_HANDLED. Any modifications to |request| will be observed.  If the URL in | ||||
|   // |request| is changed and |redirectUrl| is also set, the URL in |request| | ||||
|   // will be used. | ||||
|   /*--cef()--*/ | ||||
|   virtual RetVal HandleBeforeResourceLoad(CefRefPtr<CefBrowser> browser, | ||||
|                                      CefRefPtr<CefRequest> request, | ||||
| @@ -1637,16 +1638,19 @@ class CefSchemeHandler : public CefBase | ||||
| { | ||||
| public: | ||||
|   // Process the request. All response generation should take place in this | ||||
|   // method. If there is no response set |response_length| to zero and | ||||
|   // ReadResponse() will not be called. If the response length is not known then | ||||
|   // set |response_length| to -1 and ReadResponse() will be called until it | ||||
|   // returns false or until the value of |bytes_read| is set to 0. Otherwise, | ||||
|   // set |response_length| to a positive value and ReadResponse() will be called | ||||
|   // until it returns false, the value of |bytes_read| is set to 0 or the | ||||
|   // specified number of bytes have been read. If there is a response set | ||||
|   // |mime_type| to the mime type for the response. | ||||
|   // method. If there is no response set |response_length| to zero or return | ||||
|   // false and ReadResponse() will not be called. If the response length is not | ||||
|   // known set |response_length| to -1 and ReadResponse() will be called until | ||||
|   // it returns false or until the value of |bytes_read| is set to 0. If the | ||||
|   // response length is known set |response_length| to a positive value and | ||||
|   // ReadResponse() will be called until it returns false, the value of | ||||
|   // |bytes_read| is set to 0 or the specified number of bytes have been read. | ||||
|   // Use the |response| object to set the mime type, http status code and | ||||
|   // optional header values for the response and return true. To redirect the | ||||
|   // request to a new URL set |redirectUrl| to the new URL and return true. | ||||
|   /*--cef()--*/ | ||||
|   virtual bool ProcessRequest(CefRefPtr<CefRequest> request, | ||||
|                               CefString& redirectUrl, | ||||
|                               CefRefPtr<CefResponse> response, | ||||
|                               int* response_length) =0; | ||||
|  | ||||
|   | ||||
| @@ -644,11 +644,12 @@ typedef struct _cef_handler_t | ||||
|   // Called on the IO thread before a resource is loaded.  To allow the resource | ||||
|   // to load normally return RV_CONTINUE. To redirect the resource to a new url | ||||
|   // populate the |redirectUrl| value and return RV_CONTINUE.  To specify data | ||||
|   // for the resource return a CefStream object in |resourceStream|, set | ||||
|   // |mimeType| to the resource stream's mime type, and return RV_CONTINUE. To | ||||
|   // cancel loading of the resource return RV_HANDLED. Any modifications to | ||||
|   // |request| will be observed.  If the URL in |request| is changed and | ||||
|   // |redirectUrl| is also set, the URL in |request| will be used. | ||||
|   // for the resource return a CefStream object in |resourceStream|, use the | ||||
|   // |response| object to set mime type, HTTP status code and optional header | ||||
|   // values, and return RV_CONTINUE. To cancel loading of the resource return | ||||
|   // RV_HANDLED. Any modifications to |request| will be observed.  If the URL in | ||||
|   // |request| is changed and |redirectUrl| is also set, the URL in |request| | ||||
|   // will be used. | ||||
|   enum cef_retval_t (CEF_CALLBACK *handle_before_resource_load)( | ||||
|       struct _cef_handler_t* self, struct _cef_browser_t* browser, | ||||
|       struct _cef_request_t* request, cef_string_t* redirectUrl, | ||||
| @@ -1399,17 +1400,20 @@ typedef struct _cef_scheme_handler_t | ||||
|   cef_base_t base; | ||||
|  | ||||
|   // Process the request. All response generation should take place in this | ||||
|   // function. If there is no response set |response_length| to zero and | ||||
|   // read_response() will not be called. If the response length is not known | ||||
|   // then set |response_length| to -1 and read_response() will be called until | ||||
|   // it returns false (0) or until the value of |bytes_read| is set to 0. | ||||
|   // Otherwise, set |response_length| to a positive value and read_response() | ||||
|   // will be called until it returns false (0), the value of |bytes_read| is set | ||||
|   // to 0 or the specified number of bytes have been read. If there is a | ||||
|   // response set |mime_type| to the mime type for the response. | ||||
|   // function. If there is no response set |response_length| to zero or return | ||||
|   // false (0) and read_response() will not be called. If the response length is | ||||
|   // not known set |response_length| to -1 and read_response() will be called | ||||
|   // until it returns false (0) or until the value of |bytes_read| is set to 0. | ||||
|   // If the response length is known set |response_length| to a positive value | ||||
|   // and read_response() will be called until it returns false (0), the value of | ||||
|   // |bytes_read| is set to 0 or the specified number of bytes have been read. | ||||
|   // Use the |response| object to set the mime type, http status code and | ||||
|   // optional header values for the response and return true (1). To redirect | ||||
|   // the request to a new URL set |redirectUrl| to the new URL and return true | ||||
|   // (1). | ||||
|   int (CEF_CALLBACK *process_request)(struct _cef_scheme_handler_t* self, | ||||
|       struct _cef_request_t* request, struct _cef_response_t* response, | ||||
|       int* response_length); | ||||
|       struct _cef_request_t* request, cef_string_t* redirectUrl, | ||||
|       struct _cef_response_t* response, int* response_length); | ||||
|  | ||||
|   // Cancel processing of the request. | ||||
|   void (CEF_CALLBACK *cancel)(struct _cef_scheme_handler_t* self); | ||||
|   | ||||
| @@ -129,6 +129,12 @@ public: | ||||
|  | ||||
|   virtual bool IsRedirectResponse(GURL* location, int* http_status_code) | ||||
|   { | ||||
|     if (redirect_url_.is_valid()) { | ||||
|       // Redirect to the new URL. | ||||
|       *http_status_code = 303; | ||||
|       location->Swap(&redirect_url_); | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
| @@ -150,6 +156,7 @@ public: | ||||
|  | ||||
| protected: | ||||
|   GURL url_; | ||||
|   GURL redirect_url_; | ||||
|  | ||||
| private: | ||||
|   void DidResolve(const GURL& url) | ||||
| @@ -189,12 +196,23 @@ private: | ||||
|       static_cast<CefRequestImpl*>(req.get())->Set(owner_->request()); | ||||
|  | ||||
|       owner_->handler_->Cancel(); | ||||
|  | ||||
|       int response_length = 0; | ||||
|       CefString redirectUrl; | ||||
|  | ||||
|       // handler should complete content generation in ProcessRequest | ||||
|       bool res = owner_->handler_->ProcessRequest(req, owner_->response_, | ||||
|           &response_length); | ||||
|       if (res) | ||||
|       bool res = owner_->handler_->ProcessRequest(req, redirectUrl, | ||||
|           owner_->response_, &response_length); | ||||
|       if (res) { | ||||
|         if (!redirectUrl.empty()) { | ||||
|           // Treat the request as a redirect. | ||||
|           std::string redirectUrlStr = redirectUrl; | ||||
|           owner_->redirect_url_ = GURL(redirectUrlStr); | ||||
|           owner_->response_length_ = 0; | ||||
|         } else { | ||||
|           owner_->response_length_ = response_length; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       ////////////////////////////////////////////////////////////////////////// | ||||
|       if (owner_loop_) { | ||||
|   | ||||
| @@ -19,18 +19,20 @@ | ||||
|  | ||||
| int CEF_CALLBACK scheme_handler_process_request( | ||||
|     struct _cef_scheme_handler_t* self, cef_request_t* request, | ||||
|     cef_response_t* response, int* response_length) | ||||
|     cef_string_t* redirectUrl, cef_response_t* response, int* response_length) | ||||
| { | ||||
|   DCHECK(self); | ||||
|   DCHECK(request); | ||||
|   DCHECK(redirectUrl); | ||||
|   DCHECK(response); | ||||
|   DCHECK(response_length); | ||||
|   if(!self || !request || !response || !response_length) | ||||
|   if(!self || !request || !redirectUrl || !response || !response_length) | ||||
|     return 0; | ||||
|  | ||||
|   CefString redirectUrlStr(redirectUrl); | ||||
|   return CefSchemeHandlerCppToC::Get(self)->ProcessRequest( | ||||
|       CefRequestCToCpp::Wrap(request), CefResponseCToCpp::Wrap(response), | ||||
|       response_length); | ||||
|       CefRequestCToCpp::Wrap(request), redirectUrlStr, | ||||
|       CefResponseCToCpp::Wrap(response), response_length); | ||||
| } | ||||
|  | ||||
| void CEF_CALLBACK scheme_handler_cancel(struct _cef_scheme_handler_t* self) | ||||
|   | ||||
| @@ -18,13 +18,15 @@ | ||||
| // VIRTUAL METHODS - Body may be edited by hand. | ||||
|  | ||||
| bool CefSchemeHandlerCToCpp::ProcessRequest(CefRefPtr<CefRequest> request, | ||||
|     CefRefPtr<CefResponse> response, int* response_length) | ||||
|     CefString& redirectUrl, CefRefPtr<CefResponse> response, | ||||
|     int* response_length) | ||||
| { | ||||
|   if(CEF_MEMBER_MISSING(struct_, process_request)) | ||||
|     return false; | ||||
|  | ||||
|   return struct_->process_request(struct_, CefRequestCppToC::Wrap(request), | ||||
|       CefResponseCppToC::Wrap(response), response_length) ? true : false; | ||||
|       redirectUrl.GetWritableStruct(), CefResponseCppToC::Wrap(response), | ||||
|       response_length) ? true : false; | ||||
| } | ||||
|  | ||||
| void CefSchemeHandlerCToCpp::Cancel() | ||||
|   | ||||
| @@ -34,7 +34,8 @@ public: | ||||
|  | ||||
|   // CefSchemeHandler methods | ||||
|   virtual bool ProcessRequest(CefRefPtr<CefRequest> request, | ||||
|       CefRefPtr<CefResponse> response, int* response_length); | ||||
|       CefString& redirectUrl, CefRefPtr<CefResponse> response, | ||||
|       int* response_length); | ||||
|   virtual void Cancel(); | ||||
|   virtual bool ReadResponse(void* data_out, int bytes_to_read, int* bytes_read); | ||||
| }; | ||||
|   | ||||
| @@ -20,15 +20,18 @@ public: | ||||
|   ClientSchemeHandler() : offset_(0) {} | ||||
|  | ||||
|   // Process the request. All response generation should take place in this | ||||
|   // method. If there is no response set |response_length| to zero and | ||||
|   // ReadResponse() will not be called. If the response length is not known then | ||||
|   // set |response_length| to -1 and ReadResponse() will be called until it | ||||
|   // returns false or until the value of |bytes_read| is set to 0. Otherwise, | ||||
|   // set |response_length| to a positive value and ReadResponse() will be called | ||||
|   // until it returns false, the value of |bytes_read| is set to 0 or the | ||||
|   // specified number of bytes have been read. If there is a response set | ||||
|   // |mime_type| to the mime type for the response. | ||||
|   // method. If there is no response set |response_length| to zero or return | ||||
|   // false and ReadResponse() will not be called. If the response length is not | ||||
|   // known set |response_length| to -1 and ReadResponse() will be called until | ||||
|   // it returns false or until the value of |bytes_read| is set to 0. If the | ||||
|   // response length is known set |response_length| to a positive value and | ||||
|   // ReadResponse() will be called until it returns false, the value of | ||||
|   // |bytes_read| is set to 0 or the specified number of bytes have been read. | ||||
|   // Use the |response| object to set the mime type, http status code and | ||||
|   // optional header values for the response and return true. To redirect the | ||||
|   // request to a new URL set |redirectUrl| to the new URL and return true. | ||||
|   virtual bool ProcessRequest(CefRefPtr<CefRequest> request, | ||||
|                               CefString& redirectUrl, | ||||
|                               CefRefPtr<CefResponse> response, | ||||
|                               int* response_length) | ||||
|   { | ||||
|   | ||||
| @@ -21,16 +21,19 @@ public: | ||||
|     got_request.reset(); | ||||
|     got_read.reset(); | ||||
|     got_output.reset(); | ||||
|     got_redirect.reset(); | ||||
|   } | ||||
|  | ||||
|   std::string url; | ||||
|   std::string html; | ||||
|   int status_code; | ||||
|   std::string redirect_url; | ||||
|  | ||||
|   TrackCallback  | ||||
|     got_request, | ||||
|     got_read, | ||||
|     got_output; | ||||
|     got_output, | ||||
|     got_redirect; | ||||
| }; | ||||
|  | ||||
| class TestSchemeHandler : public TestHandler | ||||
| @@ -46,6 +49,28 @@ public: | ||||
|     CreateBrowser(test_results_->url); | ||||
|   } | ||||
|  | ||||
|   virtual RetVal HandleBeforeBrowse(CefRefPtr<CefBrowser> browser, | ||||
|                                     CefRefPtr<CefFrame> frame, | ||||
|                                     CefRefPtr<CefRequest> request, | ||||
|                                     NavType navType, bool isRedirect) | ||||
|   { | ||||
|     if (isRedirect) { | ||||
|       test_results_->got_redirect.yes(); | ||||
|       std::string newUrl = request->GetURL(); | ||||
|       EXPECT_EQ(newUrl, test_results_->redirect_url); | ||||
|  | ||||
|       // No read should have occurred for the redirect. | ||||
|       EXPECT_TRUE(test_results_->got_request); | ||||
|       EXPECT_FALSE(test_results_->got_read); | ||||
|  | ||||
|       // Now loading the redirect URL. | ||||
|       test_results_->url = test_results_->redirect_url; | ||||
|       test_results_->redirect_url.clear(); | ||||
|     } | ||||
|      | ||||
|     return RV_CONTINUE; | ||||
|   } | ||||
|  | ||||
|   virtual RetVal HandleLoadEnd(CefRefPtr<CefBrowser> browser, | ||||
|                                CefRefPtr<CefFrame> frame, | ||||
|                                int httpStatusCode) | ||||
| @@ -74,6 +99,7 @@ public: | ||||
|     : test_results_(tr), offset_(0) {} | ||||
|  | ||||
|   virtual bool ProcessRequest(CefRefPtr<CefRequest> request,  | ||||
|                               CefString& redirectUrl, | ||||
|                               CefRefPtr<CefResponse> response,  | ||||
|                               int* response_length) | ||||
|   { | ||||
| @@ -86,13 +112,16 @@ public: | ||||
|  | ||||
|     response->SetStatus(test_results_->status_code); | ||||
|  | ||||
|     bool handled = !test_results_->html.empty(); | ||||
|     if(handled) { | ||||
|     if (!test_results_->redirect_url.empty()) { | ||||
|       redirectUrl = test_results_->redirect_url; | ||||
|       return true; | ||||
|     } else if (!test_results_->html.empty()) { | ||||
|       response->SetMimeType("text/html"); | ||||
|       *response_length = test_results_->html.size(); | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     return handled; | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   virtual void Cancel() | ||||
| @@ -251,6 +280,24 @@ TEST(SchemeHandlerTest, StandardSchemeNoResponse) | ||||
|   EXPECT_FALSE(g_TestResults.got_output); | ||||
| } | ||||
|  | ||||
| // Test that a standard scheme can generate redirects. | ||||
| TEST(SchemeHandlerTest, StandardSchemeRedirect) | ||||
| { | ||||
|   CreateStandardTestScheme(); | ||||
|   g_TestResults.url = "stdscheme://tests/run.html"; | ||||
|   g_TestResults.redirect_url = "stdscheme://tests/redirect.html"; | ||||
|   g_TestResults.html = | ||||
|       "<html><head></head><body><h1>Redirected</h1></body></html>"; | ||||
|    | ||||
|   CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults); | ||||
|   handler->ExecuteTest(); | ||||
|  | ||||
|   EXPECT_TRUE(g_TestResults.got_request); | ||||
|   EXPECT_TRUE(g_TestResults.got_read); | ||||
|   EXPECT_TRUE(g_TestResults.got_output); | ||||
|   EXPECT_TRUE(g_TestResults.got_redirect); | ||||
| } | ||||
|  | ||||
| // Test that a non-standard scheme can return normal results. | ||||
| TEST(SchemeHandlerTest, NonStandardSchemeNormalResponse) | ||||
| { | ||||
| @@ -313,3 +360,21 @@ TEST(SchemeHandlerTest, NonStandardSchemeNoResponse) | ||||
|   EXPECT_FALSE(g_TestResults.got_read); | ||||
|   EXPECT_FALSE(g_TestResults.got_output); | ||||
| } | ||||
|  | ||||
| // Test that a non-standard scheme can generate redirects. | ||||
| TEST(SchemeHandlerTest, NonStandardSchemeRedirect) | ||||
| { | ||||
|   CreateNonStandardTestScheme(); | ||||
|   g_TestResults.url = "nonstdscheme:some%20value"; | ||||
|   g_TestResults.redirect_url = "nonstdscheme:some%20other%20value"; | ||||
|   g_TestResults.html = | ||||
|       "<html><head></head><body><h1>Redirected</h1></body></html>"; | ||||
|    | ||||
|   CefRefPtr<TestSchemeHandler> handler = new TestSchemeHandler(&g_TestResults); | ||||
|   handler->ExecuteTest(); | ||||
|  | ||||
|   EXPECT_TRUE(g_TestResults.got_request); | ||||
|   EXPECT_TRUE(g_TestResults.got_read); | ||||
|   EXPECT_TRUE(g_TestResults.got_output); | ||||
|   EXPECT_TRUE(g_TestResults.got_redirect); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user