diff --git a/cef.gyp b/cef.gyp index 252011d0c..f63f76daa 100644 --- a/cef.gyp +++ b/cef.gyp @@ -191,6 +191,7 @@ 'tests/unittests/dom_unittest.cc', 'tests/unittests/request_unittest.cc', 'tests/unittests/run_all_unittests.cc', + 'tests/unittests/scheme_handler_unittest.cc', 'tests/unittests/stream_unittest.cc', 'tests/unittests/string_unittest.cc', 'tests/unittests/test_handler.h', diff --git a/include/cef.h b/include/cef.h index 34786351f..ab4b1ed9b 100644 --- a/include/cef.h +++ b/include/cef.h @@ -818,7 +818,7 @@ public: CefRefPtr request, CefString& redirectUrl, CefRefPtr& resourceStream, - CefString& mimeType, + CefRefPtr response, int loadFlags) =0; // Called on the IO thread to handle requests for URLs with an unknown @@ -1235,21 +1235,33 @@ class CefResponse : public CefBase public: typedef std::map HeaderMap; - // Returns the response status code. + // Returns/sets the response status code. /*--cef()--*/ virtual int GetStatus() =0; + /*--cef()--*/ + virtual void SetStatus(int status) = 0; - // Returns the response status text. + // Returns/sets the response status text. /*--cef()--*/ virtual CefString GetStatusText() =0; + /*--cef()--*/ + virtual void SetStatusText(const CefString& statusText) = 0; + + // Returns/sets the response mime type. + /*--cef()--*/ + virtual CefString GetMimeType() = 0; + /*--cef()--*/ + virtual void SetMimeType(const CefString& mimeType) = 0; // Returns the value for the specified response header field. /*--cef()--*/ virtual CefString GetHeader(const CefString& name) =0; - // Retrieves a map of all response header fields. + // Retrieves/sets a map of all response header fields. /*--cef()--*/ virtual void GetHeaderMap(HeaderMap& headerMap) =0; + /*--cef()--*/ + virtual void SetHeaderMap(const HeaderMap& headerMap) =0; }; @@ -1635,7 +1647,8 @@ public: // |mime_type| to the mime type for the response. /*--cef()--*/ virtual bool ProcessRequest(CefRefPtr request, - CefString& mime_type, int* response_length) =0; + CefRefPtr response, + int* response_length) =0; // Cancel processing of the request. /*--cef()--*/ diff --git a/include/cef_capi.h b/include/cef_capi.h index ae13c2099..3af083b39 100644 --- a/include/cef_capi.h +++ b/include/cef_capi.h @@ -652,8 +652,8 @@ typedef struct _cef_handler_t 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, - struct _cef_stream_reader_t** resourceStream, cef_string_t* mimeType, - int loadFlags); + struct _cef_stream_reader_t** resourceStream, + struct _cef_response_t* response, int loadFlags); // Called on the IO thread to handle requests for URLs with an unknown // protocol component. Return RV_HANDLED to indicate that the request should @@ -1020,22 +1020,34 @@ typedef struct _cef_response_t // Base structure. cef_base_t base; - // Returns the response status code. + // Returns/sets the response status code. int (CEF_CALLBACK *get_status)(struct _cef_response_t* self); + void (CEF_CALLBACK *set_status)(struct _cef_response_t* self, int status); - // Returns the response status text. + // Returns/sets the response status text. // The resulting string must be freed by calling cef_string_userfree_free(). cef_string_userfree_t (CEF_CALLBACK *get_status_text)( struct _cef_response_t* self); + void (CEF_CALLBACK *set_status_text)(struct _cef_response_t* self, + const cef_string_t* statusText); + + // Returns/sets the response mime type. + // The resulting string must be freed by calling cef_string_userfree_free(). + cef_string_userfree_t (CEF_CALLBACK *get_mime_type)( + struct _cef_response_t* self); + void (CEF_CALLBACK *set_mime_type)(struct _cef_response_t* self, + const cef_string_t* mimeType); // Returns the value for the specified response header field. // The resulting string must be freed by calling cef_string_userfree_free(). cef_string_userfree_t (CEF_CALLBACK *get_header)(struct _cef_response_t* self, const cef_string_t* name); - // Retrieves a map of all response header fields. + // Retrieves/sets a map of all response header fields. void (CEF_CALLBACK *get_header_map)(struct _cef_response_t* self, cef_string_map_t headerMap); + void (CEF_CALLBACK *set_header_map)(struct _cef_response_t* self, + cef_string_map_t headerMap); } cef_response_t; @@ -1396,7 +1408,7 @@ typedef struct _cef_scheme_handler_t // 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. int (CEF_CALLBACK *process_request)(struct _cef_scheme_handler_t* self, - struct _cef_request_t* request, cef_string_t* mime_type, + struct _cef_request_t* request, struct _cef_response_t* response, int* response_length); // Cancel processing of the request. diff --git a/libcef/browser_resource_loader_bridge.cc b/libcef/browser_resource_loader_bridge.cc index 35f9bdd77..13ac1c7ab 100644 --- a/libcef/browser_resource_loader_bridge.cc +++ b/libcef/browser_resource_loader_bridge.cc @@ -42,6 +42,7 @@ #include "cef_process_io_thread.h" #include "external_protocol_handler.h" #include "request_impl.h" +#include "response_impl.h" #include "http_header_utils.h" #include "base/file_path.h" @@ -313,10 +314,10 @@ class RequestProxy : public net::URLRequest::Delegate, // Handler output will be returned in these variables CefString redirectUrl; CefRefPtr resourceStream; - CefString mimeType; - + CefRefPtr response(new CefResponseImpl()); + CefHandler::RetVal rv = handler->HandleBeforeResourceLoad( - browser_, request, redirectUrl, resourceStream, mimeType, + browser_, request, redirectUrl, resourceStream, response, loadFlags); // Observe URL from request. @@ -371,10 +372,32 @@ class RequestProxy : public net::URLRequest::Delegate, resource_stream_ = resourceStream; + CefResponseImpl* responseImpl = + static_cast(response.get()); + scoped_refptr headers( + new net::HttpResponseHeaders( + responseImpl->GenerateResponseLine())); + ResourceResponseInfo info; info.content_length = static_cast(offset); - if(!mimeType.empty()) - info.mime_type = mimeType; + info.mime_type = response->GetMimeType(); + info.headers = headers; + OnReceivedResponse(info); + AsyncReadData(); + } else if (response->GetStatus() != 0) { + // status set, but no resource stream + handled = true; + + CefResponseImpl* responseImpl = + static_cast(response.get()); + scoped_refptr headers( + new net::HttpResponseHeaders( + responseImpl->GenerateResponseLine())); + + ResourceResponseInfo info; + info.content_length = 0; + info.mime_type = response->GetMimeType(); + info.headers = headers; OnReceivedResponse(info); AsyncReadData(); } diff --git a/libcef/response_impl.cc b/libcef/response_impl.cc index 5b5bed343..1b9dba434 100644 --- a/libcef/response_impl.cc +++ b/libcef/response_impl.cc @@ -6,10 +6,16 @@ #include "response_impl.h" #include "base/logging.h" +#include "base/stringprintf.h" #include "http_header_utils.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLResponse.h" +CefResponseImpl::CefResponseImpl() + : status_code_(0) +{ +} + CefResponseImpl::CefResponseImpl(const WebKit::WebURLResponse &response) { DCHECK(!response.isNull()); @@ -18,6 +24,8 @@ CefResponseImpl::CefResponseImpl(const WebKit::WebURLResponse &response) status_code_ = response.httpStatusCode(); str = response.httpStatusText(); status_text_ = CefString(str); + str = response.mimeType(); + mime_type_ = CefString(str); HttpHeaderUtils::HeaderVisitor visitor(&header_map_); response.visitHTTPHeaderFields(&visitor); @@ -25,16 +33,44 @@ CefResponseImpl::CefResponseImpl(const WebKit::WebURLResponse &response) int CefResponseImpl::GetStatus() { + AutoLock lock_scope(this); return status_code_; } +void CefResponseImpl::SetStatus(int status) +{ + AutoLock lock_scope(this); + status_code_ = status; +} + CefString CefResponseImpl::GetStatusText() { + AutoLock lock_scope(this); return status_text_; } +void CefResponseImpl::SetStatusText(const CefString& statusText) +{ + AutoLock lock_scope(this); + status_text_ = statusText; +} + +CefString CefResponseImpl::GetMimeType() +{ + AutoLock lock_scope(this); + return mime_type_; +} + +void CefResponseImpl::SetMimeType(const CefString& mimeType) +{ + AutoLock lock_scope(this); + mime_type_ = mimeType; +} + CefString CefResponseImpl::GetHeader(const CefString& name) { + AutoLock lock_scope(this); + CefString value; HeaderMap::const_iterator it = header_map_.find(name); @@ -46,5 +82,32 @@ CefString CefResponseImpl::GetHeader(const CefString& name) void CefResponseImpl::GetHeaderMap(HeaderMap& map) { + AutoLock lock_scope(this); map = header_map_; } + +void CefResponseImpl::SetHeaderMap(const HeaderMap& headerMap) +{ + AutoLock lock_scope(this); + header_map_ = headerMap; +} + +CefString CefResponseImpl::GenerateResponseLine() +{ + AutoLock lock_scope(this); + + std::string response_line; + std::string status_text; + + if(status_text_.empty()) + status_text = (status_code_ == 200)?"OK":"ERROR"; + else + status_text = status_text_; + + base::SStringPrintf(&response_line, "HTTP/1.1 %d %s", status_code_, + status_text.c_str()); + + CefString value(response_line); + + return value; +} diff --git a/libcef/response_impl.h b/libcef/response_impl.h index 9c09b7547..99426bf29 100644 --- a/libcef/response_impl.h +++ b/libcef/response_impl.h @@ -15,18 +15,27 @@ class WebURLResponse; class CefResponseImpl : public CefThreadSafeBase { public: + CefResponseImpl(); CefResponseImpl(const WebKit::WebURLResponse& response); ~CefResponseImpl() {} // CefResponse API virtual int GetStatus(); + virtual void SetStatus(int status); virtual CefString GetStatusText(); + virtual void SetStatusText(const CefString& statusText); + virtual CefString GetMimeType(); + virtual void SetMimeType(const CefString& mimeType); virtual CefString GetHeader(const CefString& name); virtual void GetHeaderMap(HeaderMap& headerMap); + virtual void SetHeaderMap(const HeaderMap& headerMap); + + CefString GenerateResponseLine(); protected: int status_code_; CefString status_text_; + CefString mime_type_; HeaderMap header_map_; }; diff --git a/libcef/scheme_impl.cc b/libcef/scheme_impl.cc index 52fa4ca5b..aa0fbcb0b 100644 --- a/libcef/scheme_impl.cc +++ b/libcef/scheme_impl.cc @@ -10,6 +10,7 @@ #include "net/base/completion_callback.h" #include "net/base/io_buffer.h" #include "net/base/upload_data.h" +#include "net/http/http_response_headers.h" #include "net/http/http_util.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_filter.h" @@ -19,6 +20,7 @@ #include "tracker.h" #include "cef_context.h" #include "request_impl.h" +#include "response_impl.h" #include @@ -61,6 +63,7 @@ public: handler_->Cancel(); // Continue asynchronously. DCHECK(!async_resolver_); + response_ = new CefResponseImpl(); async_resolver_ = new AsyncResolver(this); CefThread::PostTask(CefThread::IO, FROM_HERE, NewRunnableMethod( async_resolver_.get(), &AsyncResolver::Resolve, url_)); @@ -116,6 +119,14 @@ public: } } + virtual void GetResponseInfo(net::HttpResponseInfo* info) { + CefResponseImpl* responseImpl = + static_cast(response_.get()); + scoped_refptr headers( + new net::HttpResponseHeaders(responseImpl->GenerateResponseLine())); + info->headers = headers; + } + virtual bool IsRedirectResponse(GURL* location, int* http_status_code) { return false; @@ -125,7 +136,7 @@ public: { DCHECK(request_); // call handler to get mime type - *mime_type = mime_type_; + *mime_type = response_->GetMimeType(); return true; } @@ -134,7 +145,7 @@ public: } CefRefPtr handler_; - std::string mime_type_; + CefRefPtr response_; int response_length_; protected: @@ -178,15 +189,13 @@ private: static_cast(req.get())->Set(owner_->request()); owner_->handler_->Cancel(); - CefString mime_type; int response_length = 0; // handler should complete content generation in ProcessRequest - bool res = owner_->handler_->ProcessRequest(req, mime_type, + bool res = owner_->handler_->ProcessRequest(req, owner_->response_, &response_length); - if (res) { - owner_->mime_type_ = mime_type; + if (res) owner_->response_length_ = response_length; - } + ////////////////////////////////////////////////////////////////////////// if (owner_loop_) { owner_loop_->PostTask(FROM_HERE, NewRunnableMethod( diff --git a/libcef_dll/cpptoc/handler_cpptoc.cc b/libcef_dll/cpptoc/handler_cpptoc.cc index de8901c56..3f62ed2ee 100644 --- a/libcef_dll/cpptoc/handler_cpptoc.cc +++ b/libcef_dll/cpptoc/handler_cpptoc.cc @@ -15,6 +15,7 @@ #include "libcef_dll/ctocpp/browser_ctocpp.h" #include "libcef_dll/ctocpp/frame_ctocpp.h" #include "libcef_dll/ctocpp/request_ctocpp.h" +#include "libcef_dll/ctocpp/response_ctocpp.h" #include "libcef_dll/ctocpp/stream_reader_ctocpp.h" #include "libcef_dll/ctocpp/v8value_ctocpp.h" @@ -197,25 +198,24 @@ enum cef_retval_t CEF_CALLBACK handler_handle_load_error( enum cef_retval_t CEF_CALLBACK handler_handle_before_resource_load( struct _cef_handler_t* self, cef_browser_t* browser, struct _cef_request_t* request, cef_string_t* redirectUrl, - struct _cef_stream_reader_t** resourceStream, cef_string_t* mimeType, - int loadFlags) + struct _cef_stream_reader_t** resourceStream, + struct _cef_response_t* response, int loadFlags) { DCHECK(self); DCHECK(browser); DCHECK(redirectUrl); DCHECK(resourceStream); - DCHECK(mimeType); - if(!self || !browser || !redirectUrl || !resourceStream || !mimeType) + DCHECK(response); + if(!self || !browser || !redirectUrl || !resourceStream || !response) return RV_CONTINUE; CefRefPtr streamPtr; CefString redirectUrlStr(redirectUrl); - CefString mimeTypeStr(mimeType); enum cef_retval_t rv = CefHandlerCppToC::Get(self)-> HandleBeforeResourceLoad(CefBrowserCToCpp::Wrap(browser), - CefRequestCToCpp::Wrap(request), redirectUrlStr, streamPtr, mimeTypeStr, - loadFlags); + CefRequestCToCpp::Wrap(request), redirectUrlStr, streamPtr, + CefResponseCToCpp::Wrap(response), loadFlags); if(streamPtr.get()) *resourceStream = CefStreamReaderCToCpp::Unwrap(streamPtr); diff --git a/libcef_dll/cpptoc/response_cpptoc.cc b/libcef_dll/cpptoc/response_cpptoc.cc index 89424da8f..de32da944 100644 --- a/libcef_dll/cpptoc/response_cpptoc.cc +++ b/libcef_dll/cpptoc/response_cpptoc.cc @@ -25,6 +25,15 @@ int CEF_CALLBACK response_get_status(struct _cef_response_t* self) return CefResponseCppToC::Get(self)->GetStatus(); } +void CEF_CALLBACK response_set_status(struct _cef_response_t* self, int status) +{ + DCHECK(self); + if(!self) + return; + + CefResponseCppToC::Get(self)->SetStatus(status); +} + cef_string_userfree_t CEF_CALLBACK response_get_status_text( struct _cef_response_t* self) { @@ -36,6 +45,37 @@ cef_string_userfree_t CEF_CALLBACK response_get_status_text( return text.DetachToUserFree(); } +void CEF_CALLBACK response_set_status_text(struct _cef_response_t* self, + const cef_string_t* statusText) +{ + DCHECK(self); + if(!self) + return; + + CefResponseCppToC::Get(self)->SetStatusText(CefString(statusText)); +} + +cef_string_userfree_t CEF_CALLBACK response_get_mime_type( + struct _cef_response_t* self) +{ + DCHECK(self); + if(!self) + return NULL; + + CefString text = CefResponseCppToC::Get(self)->GetMimeType(); + return text.DetachToUserFree(); +} + +void CEF_CALLBACK response_set_mime_type(struct _cef_response_t* self, + const cef_string_t* mimeType) +{ + DCHECK(self); + if(!self) + return; + + CefResponseCppToC::Get(self)->SetMimeType(CefString(mimeType)); +} + cef_string_userfree_t CEF_CALLBACK response_get_header( struct _cef_response_t* self, const cef_string_t* name) { @@ -59,6 +99,20 @@ void CEF_CALLBACK response_get_header_map(struct _cef_response_t* self, transfer_string_map_contents(map, headerMap); } +void CEF_CALLBACK response_set_header_map(struct _cef_response_t* self, + cef_string_map_t headerMap) +{ + DCHECK(self); + if(!self) + return; + + CefResponse::HeaderMap map; + if(headerMap) + transfer_string_map_contents(headerMap, map); + + CefResponseCppToC::Get(self)->SetHeaderMap(map); +} + // CONSTRUCTOR - Do not edit by hand. @@ -66,9 +120,14 @@ CefResponseCppToC::CefResponseCppToC(CefResponse* cls) : CefCppToC(cls) { struct_.struct_.get_status = response_get_status; + struct_.struct_.set_status = response_set_status; struct_.struct_.get_status_text = response_get_status_text; + struct_.struct_.set_status_text = response_set_status_text; + struct_.struct_.get_mime_type = response_get_mime_type; + struct_.struct_.set_mime_type = response_set_mime_type; struct_.struct_.get_header = response_get_header; struct_.struct_.get_header_map = response_get_header_map; + struct_.struct_.set_header_map = response_set_header_map; } #ifdef _DEBUG diff --git a/libcef_dll/cpptoc/scheme_handler_cpptoc.cc b/libcef_dll/cpptoc/scheme_handler_cpptoc.cc index 2e7415859..12d7f28de 100644 --- a/libcef_dll/cpptoc/scheme_handler_cpptoc.cc +++ b/libcef_dll/cpptoc/scheme_handler_cpptoc.cc @@ -12,24 +12,25 @@ #include "libcef_dll/cpptoc/scheme_handler_cpptoc.h" #include "libcef_dll/ctocpp/request_ctocpp.h" +#include "libcef_dll/ctocpp/response_ctocpp.h" // MEMBER FUNCTIONS - Body may be edited by hand. int CEF_CALLBACK scheme_handler_process_request( struct _cef_scheme_handler_t* self, cef_request_t* request, - cef_string_t* mime_type, int* response_length) + cef_response_t* response, int* response_length) { DCHECK(self); DCHECK(request); - DCHECK(mime_type); + DCHECK(response); DCHECK(response_length); - if(!self || !request || !mime_type || !response_length) + if(!self || !request || !response || !response_length) return 0; - CefString mimeTypeStr(mime_type); return CefSchemeHandlerCppToC::Get(self)->ProcessRequest( - CefRequestCToCpp::Wrap(request), mimeTypeStr, response_length); + CefRequestCToCpp::Wrap(request), CefResponseCToCpp::Wrap(response), + response_length); } void CEF_CALLBACK scheme_handler_cancel(struct _cef_scheme_handler_t* self) diff --git a/libcef_dll/ctocpp/handler_ctocpp.cc b/libcef_dll/ctocpp/handler_ctocpp.cc index a4996becf..b8502e16d 100644 --- a/libcef_dll/ctocpp/handler_ctocpp.cc +++ b/libcef_dll/ctocpp/handler_ctocpp.cc @@ -13,6 +13,7 @@ #include "libcef_dll/cpptoc/browser_cpptoc.h" #include "libcef_dll/cpptoc/frame_cpptoc.h" #include "libcef_dll/cpptoc/request_cpptoc.h" +#include "libcef_dll/cpptoc/response_cpptoc.h" #include "libcef_dll/cpptoc/stream_reader_cpptoc.h" #include "libcef_dll/cpptoc/v8value_cpptoc.h" #include "libcef_dll/ctocpp/download_handler_ctocpp.h" @@ -151,7 +152,7 @@ CefHandler::RetVal CefHandlerCToCpp::HandleLoadError( CefHandler::RetVal CefHandlerCToCpp::HandleBeforeResourceLoad( CefRefPtr browser, CefRefPtr request, CefString& redirectUrl, CefRefPtr& resourceStream, - CefString& mimeType, int loadFlags) + CefRefPtr response, int loadFlags) { if(CEF_MEMBER_MISSING(struct_, handle_before_resource_load)) return RV_CONTINUE; @@ -160,8 +161,8 @@ CefHandler::RetVal CefHandlerCToCpp::HandleBeforeResourceLoad( cef_retval_t rv = struct_->handle_before_resource_load(struct_, CefBrowserCppToC::Wrap(browser), CefRequestCppToC::Wrap(request), - redirectUrl.GetWritableStruct(), &streamRet, mimeType.GetWritableStruct(), - loadFlags); + redirectUrl.GetWritableStruct(), &streamRet, + CefResponseCppToC::Wrap(response), loadFlags); if(streamRet) resourceStream = CefStreamReaderCppToC::Unwrap(streamRet); diff --git a/libcef_dll/ctocpp/handler_ctocpp.h b/libcef_dll/ctocpp/handler_ctocpp.h index 243f0cf60..c0f05f05a 100644 --- a/libcef_dll/ctocpp/handler_ctocpp.h +++ b/libcef_dll/ctocpp/handler_ctocpp.h @@ -54,8 +54,8 @@ public: const CefString& failedUrl, CefString& errorText); virtual RetVal HandleBeforeResourceLoad(CefRefPtr browser, CefRefPtr request, CefString& redirectUrl, - CefRefPtr& resourceStream, CefString& mimeType, - int loadFlags); + CefRefPtr& resourceStream, + CefRefPtr response, int loadFlags); virtual RetVal HandleProtocolExecution(CefRefPtr browser, const CefString& url, bool& allow_os_execution); virtual RetVal HandleDownloadResponse(CefRefPtr browser, diff --git a/libcef_dll/ctocpp/response_ctocpp.cc b/libcef_dll/ctocpp/response_ctocpp.cc index 084f0af9b..fc1cd8b30 100644 --- a/libcef_dll/ctocpp/response_ctocpp.cc +++ b/libcef_dll/ctocpp/response_ctocpp.cc @@ -24,6 +24,14 @@ int CefResponseCToCpp::GetStatus() return struct_->get_status(struct_); } +void CefResponseCToCpp::SetStatus(int status) +{ + if(CEF_MEMBER_MISSING(struct_, set_status)) + return; + + struct_->set_status(struct_, status); +} + CefString CefResponseCToCpp::GetStatusText() { CefString str; @@ -35,6 +43,33 @@ CefString CefResponseCToCpp::GetStatusText() return str; } +void CefResponseCToCpp::SetStatusText(const CefString& statusText) +{ + if(CEF_MEMBER_MISSING(struct_, set_status_text)) + return; + + struct_->set_status_text(struct_, statusText.GetStruct()); +} + +CefString CefResponseCToCpp::GetMimeType() +{ + CefString str; + if(CEF_MEMBER_MISSING(struct_, get_mime_type)) + return str; + + cef_string_userfree_t strPtr = struct_->get_mime_type(struct_); + str.AttachToUserFree(strPtr); + return str; +} + +void CefResponseCToCpp::SetMimeType(const CefString& mimeType) +{ + if(CEF_MEMBER_MISSING(struct_, set_mime_type)) + return; + + struct_->set_mime_type(struct_, mimeType.GetStruct()); +} + CefString CefResponseCToCpp::GetHeader(const CefString& name) { CefString str; @@ -60,6 +95,25 @@ void CefResponseCToCpp::GetHeaderMap(HeaderMap& headerMap) cef_string_map_free(map); } +void CefResponseCToCpp::SetHeaderMap(const HeaderMap& headerMap) +{ + if(CEF_MEMBER_MISSING(struct_, set_header_map)) + return; + + cef_string_map_t map = NULL; + if(!headerMap.empty()) { + map = cef_string_map_alloc(); + if(!map) + return; + transfer_string_map_contents(headerMap, map); + } + + struct_->set_header_map(struct_, map); + + if(map) + cef_string_map_free(map); +} + #ifdef _DEBUG template<> long CefCToCpp request, - CefString& mime_type, int* response_length) + CefRefPtr response, int* response_length) { if(CEF_MEMBER_MISSING(struct_, process_request)) return false; return struct_->process_request(struct_, CefRequestCppToC::Wrap(request), - mime_type.GetWritableStruct(), response_length) ? true : false; + CefResponseCppToC::Wrap(response), response_length) ? true : false; } void CefSchemeHandlerCToCpp::Cancel() diff --git a/libcef_dll/ctocpp/scheme_handler_ctocpp.h b/libcef_dll/ctocpp/scheme_handler_ctocpp.h index f4bf6f43f..d558cb0b5 100644 --- a/libcef_dll/ctocpp/scheme_handler_ctocpp.h +++ b/libcef_dll/ctocpp/scheme_handler_ctocpp.h @@ -34,7 +34,7 @@ public: // CefSchemeHandler methods virtual bool ProcessRequest(CefRefPtr request, - CefString& mime_type, int* response_length); + CefRefPtr response, int* response_length); virtual void Cancel(); virtual bool ReadResponse(void* data_out, int bytes_to_read, int* bytes_read); }; diff --git a/tests/cefclient/cefclient.cpp b/tests/cefclient/cefclient.cpp index 2a9ab967d..6132710ac 100644 --- a/tests/cefclient/cefclient.cpp +++ b/tests/cefclient/cefclient.cpp @@ -251,14 +251,14 @@ void ClientHandler::SetEditHwnd(CefWindowHandle hwnd) void ClientHandler::SetButtonHwnds(CefWindowHandle backHwnd, CefWindowHandle forwardHwnd, - CefWindowHandle stopHwnd, - CefWindowHandle reloadHwnd) + CefWindowHandle reloadHwnd, + CefWindowHandle stopHwnd) { Lock(); m_BackHwnd = backHwnd; m_ForwardHwnd = forwardHwnd; - m_StopHwnd = stopHwnd; m_ReloadHwnd = reloadHwnd; + m_StopHwnd = stopHwnd; Unlock(); } diff --git a/tests/cefclient/cefclient.h b/tests/cefclient/cefclient.h index 739465ce2..da786c02c 100644 --- a/tests/cefclient/cefclient.h +++ b/tests/cefclient/cefclient.h @@ -128,7 +128,7 @@ public: CefRefPtr request, CefString& redirectUrl, CefRefPtr& resourceStream, - CefString& mimeType, + CefRefPtr response, int loadFlags); // Called on the IO thread to handle requests for URLs with an unknown diff --git a/tests/cefclient/cefclient_mac.mm b/tests/cefclient/cefclient_mac.mm index 7009ed620..4d11bf315 100644 --- a/tests/cefclient/cefclient_mac.mm +++ b/tests/cefclient/cefclient_mac.mm @@ -536,7 +536,7 @@ CefHandler::RetVal ClientHandler::HandleTitleChange( CefHandler::RetVal ClientHandler::HandleBeforeResourceLoad( CefRefPtr browser, CefRefPtr request, CefString& redirectUrl, CefRefPtr& resourceStream, - CefString& mimeType, int loadFlags) + CefRefPtr response, int loadFlags) { REQUIRE_IO_THREAD(); @@ -547,23 +547,28 @@ CefHandler::RetVal ClientHandler::HandleBeforeResourceLoad( DumpRequestContents(request, dump); resourceStream = CefStreamReader::CreateForData( (void*)dump.c_str(), dump.size()); - mimeType = "text/plain"; + response->SetMimeType("text/plain"); + response->SetStatus(200); } else if (strstr(url.c_str(), "/ps_logo2.png") != NULL) { // Any time we find "ps_logo2.png" in the URL substitute in our own image resourceStream = GetBinaryResourceReader("logo.png"); - mimeType = "image/png"; + response->SetMimeType("image/png"); + response->SetStatus(200); } else if(url == "http://tests/localstorage") { // Show the localstorage contents resourceStream = GetBinaryResourceReader("localstorage.html"); - mimeType = "text/html"; + response->SetMimeType("text/html"); + response->SetStatus(200); } else if(url == "http://tests/xmlhttprequest") { // Show the xmlhttprequest HTML contents resourceStream = GetBinaryResourceReader("xmlhttprequest.html"); - mimeType = "text/html"; + response->SetMimeType("text/html"); + response->SetStatus(200); } else if(url == "http://tests/domaccess") { // Show the domaccess HTML contents resourceStream = GetBinaryResourceReader("domaccess.html"); - mimeType = "text/html"; + response->SetMimeType("text/html"); + response->SetStatus(200); } return RV_CONTINUE; diff --git a/tests/cefclient/cefclient_win.cpp b/tests/cefclient/cefclient_win.cpp index d6477fb49..9752a9022 100644 --- a/tests/cefclient/cefclient_win.cpp +++ b/tests/cefclient/cefclient_win.cpp @@ -695,7 +695,7 @@ CefHandler::RetVal ClientHandler::HandleTitleChange( CefHandler::RetVal ClientHandler::HandleBeforeResourceLoad( CefRefPtr browser, CefRefPtr request, CefString& redirectUrl, CefRefPtr& resourceStream, - CefString& mimeType, int loadFlags) + CefRefPtr response, int loadFlags) { REQUIRE_IO_THREAD(); @@ -706,35 +706,43 @@ CefHandler::RetVal ClientHandler::HandleBeforeResourceLoad( DumpRequestContents(request, dump); resourceStream = CefStreamReader::CreateForData((void*)dump.c_str(), dump.size()); - mimeType = "text/plain"; + response->SetMimeType("text/plain"); + response->SetStatus(200); } else if(strstr(url.c_str(), "/ps_logo2.png") != NULL) { // Any time we find "ps_logo2.png" in the URL substitute in our own image resourceStream = GetBinaryResourceReader(IDS_LOGO); - mimeType = "image/png"; + response->SetMimeType("image/png"); + response->SetStatus(200); } else if(url == "http://tests/uiapp") { // Show the uiapp contents resourceStream = GetBinaryResourceReader(IDS_UIPLUGIN); - mimeType = "text/html"; + response->SetMimeType("text/html"); + response->SetStatus(200); } else if(url == "http://tests/osrapp") { // Show the osrapp contents resourceStream = GetBinaryResourceReader(IDS_OSRPLUGIN); - mimeType = "text/html"; + response->SetMimeType("text/html"); + response->SetStatus(200); } else if(url == "http://tests/localstorage") { // Show the localstorage contents resourceStream = GetBinaryResourceReader(IDS_LOCALSTORAGE); - mimeType = "text/html"; + response->SetMimeType("text/html"); + response->SetStatus(200); } else if(url == "http://tests/xmlhttprequest") { // Show the xmlhttprequest HTML contents resourceStream = GetBinaryResourceReader(IDS_XMLHTTPREQUEST); - mimeType = "text/html"; + response->SetMimeType("text/html"); + response->SetStatus(200); } else if(url == "http://tests/domaccess") { // Show the domaccess HTML contents resourceStream = GetBinaryResourceReader(IDS_DOMACCESS); - mimeType = "text/html"; + response->SetMimeType("text/html"); + response->SetStatus(200); } else if(strstr(url.c_str(), "/logoball.png") != NULL) { // Load the "logoball.png" image resource. resourceStream = GetBinaryResourceReader(IDS_LOGOBALL); - mimeType = "image/png"; + response->SetMimeType("image/png"); + response->SetStatus(200); } return RV_CONTINUE; } diff --git a/tests/cefclient/res/xmlhttprequest.html b/tests/cefclient/res/xmlhttprequest.html index e161d0771..638c63c82 100644 --- a/tests/cefclient/res/xmlhttprequest.html +++ b/tests/cefclient/res/xmlhttprequest.html @@ -7,7 +7,7 @@ function execXMLHttpRequest() xhr.open("GET",document.getElementById("url").value,false); xhr.setRequestHeader('My-Custom-Header', 'Some Value'); xhr.send(); - document.getElementById('ta').value = "Request\n\n"+xhr.responseText; + document.getElementById('ta').value = "Status Code: "+xhr.status+"\n\n"+xhr.responseText; }
diff --git a/tests/cefclient/scheme_test.cpp b/tests/cefclient/scheme_test.cpp index f296b4773..c8df06052 100644 --- a/tests/cefclient/scheme_test.cpp +++ b/tests/cefclient/scheme_test.cpp @@ -29,7 +29,8 @@ public: // specified number of bytes have been read. If there is a response set // |mime_type| to the mime type for the response. virtual bool ProcessRequest(CefRefPtr request, - CefString& mime_type, int* response_length) + CefRefPtr response, + int* response_length) { REQUIRE_IO_THREAD(); @@ -60,7 +61,8 @@ public: handled = true; // Set the resulting mime type - mime_type = "text/html"; + response->SetMimeType("text/html"); + response->SetStatus(200); } else if(strstr(url.c_str(), "client.png") != NULL) { // Load the response image @@ -70,7 +72,9 @@ public: if(LoadBinaryResource(IDS_LOGO, dwSize, pBytes)) { data_ = std::string(reinterpret_cast(pBytes), dwSize); handled = true; - mime_type = "image/png"; + // Set the resulting mime type + response->SetMimeType("image/jpg"); + response->SetStatus(200); } #elif defined(__APPLE__) if(LoadBinaryResource("logo.png", data_)) { diff --git a/tests/unittests/request_unittest.cc b/tests/unittests/request_unittest.cc index 95d13eb7f..229519d34 100644 --- a/tests/unittests/request_unittest.cc +++ b/tests/unittests/request_unittest.cc @@ -259,7 +259,7 @@ public: CefRefPtr request, CefString& redirectUrl, CefRefPtr& resourceStream, - CefString& mimeType, + CefRefPtr response, int loadFlags) { g_RequestSendRecvTestHandlerHandleBeforeResourceLoadCalled = true; diff --git a/tests/unittests/scheme_handler_unittest.cc b/tests/unittests/scheme_handler_unittest.cc new file mode 100644 index 000000000..1a57975c1 --- /dev/null +++ b/tests/unittests/scheme_handler_unittest.cc @@ -0,0 +1,315 @@ +// Copyright (c) 2011 The Chromium Embedded Framework 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 "test_handler.h" + +namespace { + +class TestResults +{ +public: + TestResults() + { + } + + void reset() + { + url.clear(); + html.clear(); + status_code = 0; + got_request.reset(); + got_read.reset(); + got_output.reset(); + } + + std::string url; + std::string html; + int status_code; + + TrackCallback + got_request, + got_read, + got_output; +}; + +class TestSchemeHandler : public TestHandler +{ +public: + TestSchemeHandler(TestResults* tr) + : test_results_(tr) + { + } + + virtual void RunTest() + { + CreateBrowser(test_results_->url); + } + + virtual RetVal HandleLoadEnd(CefRefPtr browser, + CefRefPtr frame, + int httpStatusCode) + { + // Test that the output is correct. + std::string output = frame->GetSource(); + if (output == test_results_->html) + test_results_->got_output.yes(); + + // Test that the status code is correct. + EXPECT_EQ(httpStatusCode, test_results_->status_code); + + DestroyTest(); + + return RV_CONTINUE; + } + +protected: + TestResults* test_results_; +}; + +class ClientSchemeHandler : public CefThreadSafeBase +{ +public: + ClientSchemeHandler(TestResults* tr) + : test_results_(tr), offset_(0) {} + + virtual bool ProcessRequest(CefRefPtr request, + CefRefPtr response, + int* response_length) + { + EXPECT_TRUE(CefCurrentlyOn(TID_IO)); + + test_results_->got_request.yes(); + + std::string url = request->GetURL(); + EXPECT_EQ(url, test_results_->url); + + response->SetStatus(test_results_->status_code); + + bool handled = !test_results_->html.empty(); + if(handled) { + response->SetMimeType("text/html"); + *response_length = test_results_->html.size(); + } + + return handled; + } + + virtual void Cancel() + { + EXPECT_TRUE(CefCurrentlyOn(TID_IO)); + } + + virtual bool ReadResponse(void* data_out, int bytes_to_read, int* bytes_read) + { + EXPECT_TRUE(CefCurrentlyOn(TID_IO)); + + test_results_->got_read.yes(); + + bool has_data = false; + *bytes_read = 0; + + Lock(); + + size_t size = test_results_->html.size(); + if(offset_ < size) { + int transfer_size = + std::min(bytes_to_read, static_cast(size - offset_)); + memcpy(data_out, test_results_->html.c_str() + offset_, transfer_size); + offset_ += transfer_size; + + *bytes_read = transfer_size; + has_data = true; + } + + Unlock(); + + return has_data; + } + +private: + TestResults* test_results_; + size_t offset_; +}; + +class ClientSchemeHandlerFactory : + public CefThreadSafeBase +{ +public: + ClientSchemeHandlerFactory(TestResults* tr) + : test_results_(tr){} + + virtual CefRefPtr Create() + { + EXPECT_TRUE(CefCurrentlyOn(TID_IO)); + return new ClientSchemeHandler(test_results_); + } + + TestResults* test_results_; +}; + +// Global test results object. +TestResults g_TestResults; + +void CreateStandardTestScheme() +{ + g_TestResults.reset(); + static bool registered = false; + if (!registered) { + CefRegisterScheme("stdscheme", "tests", true, + new ClientSchemeHandlerFactory(&g_TestResults)); + registered = true; + } +} + +void CreateNonStandardTestScheme() +{ + g_TestResults.reset(); + static bool registered = false; + if (!registered) { + CefRegisterScheme("nonstdscheme", CefString(), false, + new ClientSchemeHandlerFactory(&g_TestResults)); + registered = true; + } +} + +} // anonymous + +// Test that a standard scheme can return normal results. +TEST(SchemeHandlerTest, StandardSchemeNormalResponse) +{ + CreateStandardTestScheme(); + g_TestResults.url = "stdscheme://tests/run.html"; + g_TestResults.html = + "

Success!

"; + g_TestResults.status_code = 200; + + CefRefPtr 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); +} + +// Test that a standard scheme can return an error code. +TEST(SchemeHandlerTest, StandardSchemeErrorResponse) +{ + CreateStandardTestScheme(); + g_TestResults.url = "stdscheme://tests/run.html"; + g_TestResults.html = + "

404

"; + g_TestResults.status_code = 404; + + CefRefPtr 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); +} + +// Test that standard scheme handling fails when the scheme name is incorrect. +TEST(SchemeHandlerTest, StandardSchemeNameNotHandled) +{ + CreateStandardTestScheme(); + g_TestResults.url = "stdscheme2://tests/run.html"; + + CefRefPtr handler = new TestSchemeHandler(&g_TestResults); + handler->ExecuteTest(); + + EXPECT_FALSE(g_TestResults.got_request); + EXPECT_FALSE(g_TestResults.got_read); + EXPECT_FALSE(g_TestResults.got_output); +} + +// Test that standard scheme handling fails when the domain name is incorrect. +TEST(SchemeHandlerTest, StandardSchemeDomainNotHandled) +{ + CreateStandardTestScheme(); + g_TestResults.url = "stdscheme://tests2/run.html"; + + CefRefPtr handler = new TestSchemeHandler(&g_TestResults); + handler->ExecuteTest(); + + EXPECT_FALSE(g_TestResults.got_request); + EXPECT_FALSE(g_TestResults.got_read); + EXPECT_FALSE(g_TestResults.got_output); +} + +// Test that a standard scheme can return no response. +TEST(SchemeHandlerTest, StandardSchemeNoResponse) +{ + CreateStandardTestScheme(); + g_TestResults.url = "stdscheme://tests/run.html"; + + CefRefPtr handler = new TestSchemeHandler(&g_TestResults); + handler->ExecuteTest(); + + EXPECT_TRUE(g_TestResults.got_request); + EXPECT_FALSE(g_TestResults.got_read); + EXPECT_FALSE(g_TestResults.got_output); +} + +// Test that a non-standard scheme can return normal results. +TEST(SchemeHandlerTest, NonStandardSchemeNormalResponse) +{ + CreateNonStandardTestScheme(); + g_TestResults.url = "nonstdscheme:some%20value"; + g_TestResults.html = + "

Success!

"; + g_TestResults.status_code = 200; + + CefRefPtr 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); +} + +// Test that a non-standard scheme can return an error code. +TEST(SchemeHandlerTest, NonStandardSchemeErrorResponse) +{ + CreateNonStandardTestScheme(); + g_TestResults.url = "nonstdscheme:some%20value"; + g_TestResults.html = + "

404

"; + g_TestResults.status_code = 404; + + CefRefPtr 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); +} + +// Test that non-standard scheme handling fails when the scheme name is +// incorrect. +TEST(SchemeHandlerTest, NonStandardSchemeNameNotHandled) +{ + CreateNonStandardTestScheme(); + g_TestResults.url = "nonstdscheme2:some%20value"; + + CefRefPtr handler = new TestSchemeHandler(&g_TestResults); + handler->ExecuteTest(); + + EXPECT_FALSE(g_TestResults.got_request); + EXPECT_FALSE(g_TestResults.got_read); + EXPECT_FALSE(g_TestResults.got_output); +} + +// Test that a non-standard scheme can return no response. +TEST(SchemeHandlerTest, NonStandardSchemeNoResponse) +{ + CreateNonStandardTestScheme(); + g_TestResults.url = "nonstdscheme:some%20value"; + + CefRefPtr handler = new TestSchemeHandler(&g_TestResults); + handler->ExecuteTest(); + + EXPECT_TRUE(g_TestResults.got_request); + EXPECT_FALSE(g_TestResults.got_read); + EXPECT_FALSE(g_TestResults.got_output); +} diff --git a/tests/unittests/test_handler.h b/tests/unittests/test_handler.h index 6892711a0..7904707d9 100644 --- a/tests/unittests/test_handler.h +++ b/tests/unittests/test_handler.h @@ -15,6 +15,7 @@ public: TrackCallback(): gotit_(false) {} void yes() { gotit_ = true; } bool isSet() { return gotit_; } + void reset() { gotit_ = false; } operator bool() const { return gotit_; } protected: bool gotit_; @@ -111,7 +112,7 @@ public: CefRefPtr request, CefString& redirectUrl, CefRefPtr& resourceStream, - CefString& mimeType, + CefRefPtr response, int loadFlags) { Lock(); @@ -122,7 +123,8 @@ public: // Return the previously mapped resource resourceStream = CefStreamReader::CreateForData( (void*)it->second.first.c_str(), it->second.first.length()); - mimeType = it->second.second; + response->SetMimeType(it->second.second); + response->SetStatus(200); } } Unlock();