Exposing a version of XMLHttpRequest to C++ code

Having problems with building or using CEF's C/C++ APIs? This forum is here to help. Please do not post bug reports or feature requests here.

Exposing a version of XMLHttpRequest to C++ code

Postby gusverdun » Mon Jan 31, 2011 5:20 pm

I am interested in adding support for this and just wanted to check if (1) I am blind (this has been done) and (2) would there be any objections to this?

In my specific case I need, for authentication purposes, to have my client issue an HTTP POST request to a website that, for security, will not support CORS.

I plan on exposing this functionality via a class called CefWebUrlRequest and CefWebUrlRequestListener (for callbacks).

Clients can then use this by creating a listener object for their needs and instantiating a CefWebUrlRequest object (like you instantiate XMLHttpRequest).

In looking at the code, it seems the best way to add this is to create my own ResourceLoaderBridge::Peer handler and call ResourceLoaderBridge::Create(request_info_) to initiate this so that it follows the CEF/Chromium threading model.

Advice?
gusverdun
Techie
 
Posts: 25
Joined: Tue Jan 11, 2011 9:08 am

Re: Exposing a version of XMLHttpRequest to C++ code

Postby magreenblatt » Mon Jan 31, 2011 6:56 pm

(1) I am blind (this has been done)

It hasn't been done, and there is (sort of) an issue for it:
http://code.google.com/p/chromiumembedd ... tail?id=51

(2) would there be any objections to this?

Nope :-).

In looking at the code, it seems the best way to add this is to create my own ResourceLoaderBridge::Peer handler and call ResourceLoaderBridge::Create(request_info_) to initiate this so that it follows the CEF/Chromium threading model.

You'll likely find it easier to use WebURLLoaderImpl (from webkit/glue/weburlloader_impl.h) and create your own implementation of WebKit::WebURLLoaderClient. WebURLLoaderImpl is the class that WebKit uses for interfacing with ResourceLoaderBridge.

Regards,
Marshall
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: Exposing a version of XMLHttpRequest to C++ code

Postby gusverdun » Thu Feb 03, 2011 11:28 am

Thanks for the tips. Here is my proposed API:

cef_types.h:
Code: Select all
enum cef_weburlrequest_flags_t
{
  WUR_FLAG_SKIP_CACHE = 0x1,
  WUR_FLAG_ALLOW_CACHED_CREDENTIALS = 0x2,
  WUR_FLAG_ALLOW_COOKIES = 0x4,
  WUR_FLAG_REPORT_UPLOAD_PROGRESS = 0x8,
  WUR_FLAG_REPORT_LOAD_TIMING = 0x10,
  WUR_FLAG_REPORT_RAW_HEADERS = 0x20
};

enum cef_weburlrequest_state_t
{
  WUR_STATE_UNSENT = 0,
  WUR_STATE_STARTED = 1,
  WUR_STATE_HEADERS_RECEIVED = 2,
  WUR_STATE_LOADING = 3,
  WUR_STATE_DONE = 4,
  WUR_STATE_ERROR = 5,
};

cef.h:
Code: Select all
// Class used to make a web URL request
/*--cef(source=library)--*/
class CefWebUrlRequest : public CefBase
{
public:
    typedef cef_weburlrequest_state_t RequestState;
    typedef cef_weburlrequest_flags_t RequestFlags;

    // Create a new CefWebUrlReqeust object.
    /*--cef()--*/
    static CefRefPtr<CefWebUrlRequest> CreateWebUrlRequest();

    // Sets the request parameters
    /*--cef()--*/
    virtual void Open(CefRefPtr<CefRequest> request) = 0;

    // Sets the request flags
    /*--cef()--*/
    virtual void SetFlags(RequestFlags flags) = 0;

    // Sets the URL to the first party for cookies
    /*--cef()--*/
    virtual void SetFirstPartyForCookies(const CefString& url) = 0;

    // Starts the request asynchronously
    /*--cef()--*/
    virtual void Send(CefRefPtr<CefWebUrlRequestHandler> callback) = 0;

    // Gets the current ready state of the request
    /*--cef()--*/
    virtual RequestState GetState() = 0;

    // Gets the response status code
    // (valid on or after WUR_STATE_HEADERS_RECEIVED)
    /*--cef()--*/
    virtual int GetHttpStatusCode() = 0;

    // Gets the response status text
    // (valid on or after WUR_STATE_HEADERS_RECEIVED)
    /*--cef()--*/
    virtual CefString GetHttpStatusText() = 0;

    // Gets the value for the specified response header field
    // (valid on or after WUR_STATE_HEADERS_RECEIVED)
    /*--cef()--*/
    virtual CefString GetHttpHeaderForField(const CefString& name) = 0;

    // Return the number of bytes in response.
    // (valid on WUR_STATE_DONE)
    /*--cef()--*/
    virtual size_t GetContentLength() = 0;

    // Read up to |size| bytes into |bytes| and return the number of bytes
    // actually read.
    // (valid on WUR_STATE_DONE)
    /*--cef()--*/
    virtual size_t GetContents(size_t size, void* bytes) = 0;
};

// Interface that should be implemented to listen for events from a CefWebUrlRequest.
/*--cef(source=client)--*/
class CefWebUrlRequestHandler : public CefBase
{
public:
  typedef cef_weburlrequest_state_t RequestState;

  // Notifies the handler that the request has started
  /*--cef()--*/
  virtual void OnStateChange(CefRefPtr<CefWebUrlRequest> request,
                             RequestState state) = 0;

  // Notifies the handler of the upload progress
  /*--cef()--*/
  virtual void OnProgress(CefRefPtr<CefWebUrlRequest> request,
                          uint64 bytesSent,
                          uint64 totalBytesToBeSent) = 0;

  // Notifies the handler that the request ended with an error.
  // domain is a namespace for "reason".
  /*--cef()--*/
  virtual void OnError(CefRefPtr<CefWebUrlRequest> request, const CefString& domain, int reason) = 0;
};

Does this seem reasonable?
gusverdun
Techie
 
Posts: 25
Joined: Tue Jan 11, 2011 9:08 am

Re: Exposing a version of XMLHttpRequest to C++ code

Postby magreenblatt » Thu Feb 03, 2011 12:03 pm

I see the following potential flaws with your API proposal.

1. It doesn't deliver response data to the handler as the data becomes available. The response data may be large so it doesn't make sense to cache this data internally.
2. It doesn't provide a mechanism for user control of redirect responses.

Are you using WebURLLoaderImpl? If so, an API that more closely follows WebURLLoader and WebURLLoaderClient would probably be better.
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: Exposing a version of XMLHttpRequest to C++ code

Postby gusverdun » Thu Feb 03, 2011 1:35 pm

I was trying to make it behave more like the way XMLHttpRequest works. But you are right, I could generalize it so that the clients can optimize for their needs.

I'll post version 2 latter today.

Yes, this will be using WebURLLoaderImpl.
gusverdun
Techie
 
Posts: 25
Joined: Tue Jan 11, 2011 9:08 am

Re: Exposing a version of XMLHttpRequest to C++ code

Postby gusverdun » Thu Feb 03, 2011 6:19 pm

Version 2

I think it will be better if I extend CefRequest with the flags and firstPartyForCookies properties so that I can keep that data together. Those two parameters would only matter for CefWebUrlRequest.

I am introducing a CefResponse read-only object to represent the WebKit::WebURLResponse data used in both the OnRedirect and OnHeadersReceived.

I cleaned up CefWebUrlRequest so that it now just manages the transaction and otherwise has no info on its results. It will be up the handler to keep the data it wants for future reference. (Should this be called CefWebUrlRequestor?)

Lastly, I added more callbacks to the CefWebUrlRequestHandler to support OnRedirect, OnHeadersReceived, and OnData.

cef_types.h did not change.

cef.h (CefRequest) change:
Code: Select all
// Class used to represent a web request.
/*--cef(source=library)--*/
class CefRequest : public CefBase
{
public:
 /////// existing methods did not change... just extended it with:

  // Optional flags. (Used By CefWebUrlRequest)
  /*--cef()--*/
  virtual int GetFlags() = 0;
  /*--cef()--*/
  virtual void SetFlags(int flags) = 0;

  // Optional URL to the first party for cookies (Used By CefWebUrlRequest)
  /*--cef()--*/
  virtual CefString GetFirstPartyForCookies() = 0;
  /*--cef()--*/
  virtual void SetFirstPartyForCookies(const CefString& url) = 0;
};

and the new classes:
Code: Select all
// Class used to make a web URL request
/*--cef(source=library)--*/
class CefWebUrlRequest : public CefBase
{
public:
    typedef cef_weburlrequest_state_t RequestState;
    typedef cef_weburlrequest_flags_t RequestFlags;

    // Create a new CefWebUrlReqeust object.
    /*--cef()--*/
    static CefRefPtr<CefWebUrlRequest> CreateWebUrlRequest();

    // Sets the request parameters
    /*--cef()--*/
    virtual void Open(CefRefPtr<CefRequest> request) = 0;

    // Starts the request asynchronously
    /*--cef()--*/
    virtual void Send(CefRefPtr<CefWebUrlRequestHandler> callback) = 0;

    // Cancels the request
    /*--cef()--*/
    virtual void Cancel() = 0;

    // Gets the current ready state of the request
    /*--cef()--*/
    virtual RequestState GetState() = 0;
};


// Class used to access the response data.
/*--cef(source=library)--*/
class CefResponse : public CefBase
{
public:
    // Gets the response status code
    /*--cef()--*/
    virtual int GetStatus() = 0;

    // Gets the response status text
    /*--cef()--*/
    virtual CefString GetStatusText() = 0;

    // Gets the value for the specified response header field
    /*--cef()--*/
    virtual CefString GetHeader(const CefString& name) = 0;

    // Gets all response headers.
    /*--cef()--*/
    virtual CefString GetAllHeaders() = 0;
};


// Interface that should be implemented to listen for events from a CefWebUrlRequest.
/*--cef(source=client)--*/
class CefWebUrlRequestHandler : public CefBase
{
public:
  typedef cef_weburlrequest_state_t RequestState;

  // Notifies the handler that the request has started
  /*--cef()--*/
  virtual void OnStateChange(CefRefPtr<CefWebUrlRequest> request,
                             RequestState state) = 0;

  // Notifies the handler that the request has been redirected and
  // provides a chance to change the request parameters.
  /*--cef()--*/
  virtual void OnRedirect(CefRefPtr<CefWebUrlRequest> webRequest,
                          CefRefPtr<CefRequest> redirect, CefRefPtr<CefResponse> response) = 0;

  // Notifies the handler of the response data.
  /*--cef()--*/
  virtual void OnHeadersReceived(CefRefPtr<CefWebUrlRequest> webRequest,
                          CefRefPtr<CefResponse> response) = 0;

  // Notifies the handler of the upload progress
  /*--cef()--*/
  virtual void OnProgress(CefRefPtr<CefWebUrlRequest> request,
                          uint64 bytesSent,
                          uint64 totalBytesToBeSent) = 0;

  // Provides the response contents as received.
  /*--cef()--*/
  virtual void OnData(CefRefPtr<CefWebUrlRequest> request, const void* data, int dataLength) = 0;

  // Notifies the handler that the request ended with an error.
  // domain is a namespace for "reason".
  /*--cef()--*/
  virtual void OnError(CefRefPtr<CefWebUrlRequest> request, const CefString& domain, int reason) = 0;
};

How does this look?
gusverdun
Techie
 
Posts: 25
Joined: Tue Jan 11, 2011 9:08 am

Re: Exposing a version of XMLHttpRequest to C++ code

Postby magreenblatt » Thu Feb 03, 2011 7:33 pm

A few things...

I think it will be better if I extend CefRequest with the flags and firstPartyForCookies properties so that I can keep that data together. Those two parameters would only matter for CefWebUrlRequest.

1. I don't really like the idea of adding parameters to CefRequest that are only used by CefWebUrlRequest. Instead, let's make |flags| and |firstPartyForCookies| parameters to Open and provide getters for them on CefWebUrlRequest if necessary.

// Sets the request parameters
/*--cef()--*/
virtual void Open(CefRefPtr<CefRequest> request) = 0;

// Starts the request asynchronously
/*--cef()--*/
virtual void Send(CefRefPtr<CefWebUrlRequestHandler> callback) = 0;

2a. Do Open and Send need to be separate methods? If someone will always call Open and then immediately call Send then it probably makes sense to have a single method that does both.

2b. Can a CefWebUrlRequestHandler object be re-used? If not, then we could potentially eliminate both Open and Send and instead pass |request|, |flags|, |firstPartyForCookies| and |callback| parameters to the static CreateWebUrlRequest method.

/ Gets the value for the specified response header field
/*--cef()--*/
virtual CefString GetHeader(const CefString& name) = 0;

// Gets all response headers.
/*--cef()--*/
virtual CefString GetAllHeaders() = 0;

3. CefResponse should provide a GetHeaderMap method to maintain consistency with CefRequest if possible.

// Notifies the handler that the request ended with an error.
// domain is a namespace for "reason".
/*--cef()--*/
virtual void OnError(CefRefPtr<CefWebUrlRequest> request, const CefString& domain, int reason) = 0;

4. What type of values will the |domain| parameter have?

(Should this be called CefWebUrlRequestor?)

5. Maybe CefWebUrlRequestClient or CefWebUrlRequestListener? Name the parameter |client| or |listener| respectively.
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: Exposing a version of XMLHttpRequest to C++ code

Postby gusverdun » Thu Feb 03, 2011 8:39 pm

1. I don't really like the idea of adding parameters to CefRequest that are only used by CefWebUrlRequest. Instead, let's make |flags| and |firstPartyForCookies| parameters to Open and provide getters for them on CefWebUrlRequest if necessary.


The problem is that |flags| and |firstPartyForCookies| need to be mutable during redirects; moving them to CefRequest seemed like the most logical choice.

2a. Do Open and Send need to be separate methods? If someone will always call Open and then immediately call Send then it probably makes sense to have a single method that does both.
2b. Can a CefWebUrlRequestHandler object be re-used? If not, then we could potentially eliminate both Open and Send and instead pass |request|, |flags|, |firstPartyForCookies| and |callback| parameters to the static CreateWebUrlRequest method.


Agreed, they don't make sense as long as |flags| and |firstPartyForCookies| is in CefRequest. If so, I can remove the Open call.

CefWebUrlRequestHandler objects can be re-used, they just have to release their CefWebUrlRequest object and create a new one to start over.

3. CefResponse should provide a GetHeaderMap method to maintain consistency with CefRequest if possible.


Will add that one.

4. What type of values will the |domain| parameter have?


I am only aware of one: "net". This is really just a way for developers to debug why something failed. The data comes from the WebURLError structure that is for diagnostic purposes. In this case "net" means Chrome's net library and the reason code is one of the constants in src\net\base\net_error_list.h. An example is "net" with reason -105: NET_ERROR(NAME_NOT_RESOLVED, -105).

5. Maybe CefWebUrlRequestClient or CefWebUrlRequestListener? Name the parameter |client| or |listener| respectively.


I like Client - Listener could get confusing with the "Handler".

Thanks!

-Gus
gusverdun
Techie
 
Posts: 25
Joined: Tue Jan 11, 2011 9:08 am

Re: Exposing a version of XMLHttpRequest to C++ code

Postby magreenblatt » Thu Feb 03, 2011 9:40 pm

The problem is that |flags| and |firstPartyForCookies| need to be mutable during redirects; moving them to CefRequest seemed like the most logical choice.

OK, let's put them in CefRequest.

CefWebUrlRequestHandler objects can be re-used, they just have to release their CefWebUrlRequest object and create a new one to start over.

I think I'd rather keep things simple and use CefWebUrlRequest as one-shot objects. That will also be less confusing for the user. Let's add the parameters to the static method and get rid of Open and Send.

I am only aware of one: "net". This is really just a way for developers to debug why something failed.

The |errorCode| parameter to HandleLoadError is used for the same purpose. You can use that enumeration here as well and get rid of the |domain| parameter.

I like Client - Listener could get confusing with the "Handler".

Client it is, then :-).
magreenblatt
Site Admin
 
Posts: 12382
Joined: Fri May 29, 2009 6:57 pm

Re: Exposing a version of XMLHttpRequest to C++ code

Postby gusverdun » Mon Feb 07, 2011 11:27 am

I attached a patch to the bug.

http://code.google.com/p/chromiumembedd ... tail?id=51

Thanks,

Gus
gusverdun
Techie
 
Posts: 25
Joined: Tue Jan 11, 2011 9:08 am


Return to Support Forum

Who is online

Users browsing this forum: Google [Bot] and 35 guests