Question

I have written a local DataSource because from what I know there are none included in Awesomium, but the thing is that it request everything from the data source html, images etc And I have no clue on how I should load all types of mime formats. My current code only supports html/text, where I load the file into binary and send as a response. This does not work for images.

Does anybody know where I should go on from here?

class LocalDataSource : 
    public Awesomium::DataSource
{
public:
    LocalDataSource() { }
    virtual ~LocalDataSource() { }

    virtual void OnRequest(int request_id, const Awesomium::WebString& path)
    {
        std::string filepath = Awesomium::ToString(path).insert(0, "./");
        std::basic_ifstream<char> is(filepath, std::ios_base::in | std::ios_base::binary);
        if (is)
        {
            is.seekg(0, is.end);
            int length = is.tellg();
            is.seekg(0, is.beg);

            char *buffer = new char[length + 1];
            is.read(buffer, length);
            buffer[length] = '\0';
            is.close();

            SendResponse(request_id, strlen(buffer), (unsigned char*)buffer, Awesomium::WSLit("text/html"));
            delete[] buffer;
        }
        else
        {
            // Error 
        }
    }
};

EDIT:

for now I will load the file relative to the executable and not use DataSource's.

Was it helpful?

Solution

I know this is old, but it was relevant to me, I fixed this the same way as Steven did, I will post the C++ code I used:

bool ResInterceptor::OnFilterNavigation(int origin_process, int origin_routing_id, const Awesomium::WebString& method, const Awesomium::WebURL& url, bool is_main_frame) 
{
    return false;
}

Awesomium::ResourceResponse* ResInterceptor::OnRequest(Awesomium::ResourceRequest* request)
{
    bool isAsset = std::strcmp(ToString(request->url().scheme()).c_str(), "asset")==0;
    bool isFile = std::strcmp(ToString(request->url().scheme()).c_str(), "file")==0;

    if(!isAsset && !isFile)
    {
        //if it is neither of these we "may" still intercept the call, this allows for offline-online versions to work
        return Awesomium::ResourceInterceptor::OnRequest(request);
    }

    if(isAsset)
    {
        //Blah blah, do whatever
    }
    else if(isFile)
    {
        //Blah blah, same
    }

    //As you can see this isn't very, but it worked for my purposes
    std::string contentpath = "E:/Location/of/files" + ToString(request->url().path()); 

    Awesomium::WebString datatype;
    std::string filename = Awesomium::ToString(request->url().filename());

    //I still want to check for the correct mime type
    if     (has_suffix(filename, ".html")) datatype = Awesomium::WSLit("text/html");
    else if(has_suffix(filename, ".js"))   datatype = Awesomium::WSLit("text/javascript");
    else if(has_suffix(filename, ".css"))  datatype = Awesomium::WSLit("text/css");
    else if(has_suffix(filename, ".swf"))  datatype = Awesomium::WSLit("application/x-shockwave-flash");
    else if(has_suffix(filename, ".zip"))  datatype = Awesomium::WSLit("application/zip");
    else if(has_suffix(filename, ".txt"))  datatype = Awesomium::WSLit("text/plain");
    else if(has_suffix(filename, ".text")) datatype = Awesomium::WSLit("text/plain");
    else if(has_suffix(filename, ".png"))  datatype = Awesomium::WSLit("image/png");
    else if(has_suffix(filename, ".jpeg")) datatype = Awesomium::WSLit("image/jpeg");
    else if(has_suffix(filename, ".jpg"))  datatype = Awesomium::WSLit("image/jpeg");
    else if(has_suffix(filename, ".webm")) datatype = Awesomium::WSLit("video/webm");
    else if(has_suffix(filename, ".mp4"))  datatype = Awesomium::WSLit("video/mp4");
    else if(has_suffix(filename, ".ogv"))  datatype = Awesomium::WSLit("video/ogg");
    else if(has_suffix(filename, ".flv"))  datatype = Awesomium::WSLit("video/flv");

    if(!datatype.IsEmpty())
    {
        FILE * pFile;
        long lSize;
        unsigned char * buffer;
        size_t result;

        pFile = fopen ( contentpath.c_str() , "rb" );
        if (pFile!=NULL)
        {
            // obtain file size:
            fseek (pFile , 0 , SEEK_END);
            lSize = ftell (pFile);
            rewind (pFile);

            // allocate memory to contain the whole file:
            buffer = (unsigned char*) malloc (sizeof(unsigned char)*lSize);
            if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}

            // copy the file into the buffer:
            result = fread (buffer,1,lSize,pFile);
            if (result != lSize) {fputs ("Reading error",stderr); exit (3);}

            //This is where the magic happens!!
            return Awesomium::ResourceResponse::Create(lSize, buffer, datatype);

            // terminate
            fclose (pFile);
            free (buffer);
        }
        else
        {
            //send this off to the default request handler instead of it being a local file
            return Awesomium::ResourceInterceptor::OnRequest(request);
        }
    }else
    {
        //send this off to the default request handler instead of it being a local file
        return Awesomium::ResourceInterceptor::OnRequest(request);
    }
}

//Support function
bool ResInterceptor::has_suffix(const std::string &str, const std::string &suffix)
{
    return str.size() >= suffix.size() &&
           str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
}

as for how I hooked it up, I simply added this line of code:

_web_core = WebCore::Initialize(config);
_web_core->set_resource_interceptor(new ResInterceptor());

This took me a whole night to nail down all because I was passing in a pointer with a variable and not using the "new" keyword directly! I got it now at least!

also note, I tried the exact same code above inside the LocalDataSource and it didn't work for anything except the text files, so I think there is a bug in there, good news is, this works the exact same way, but you get more control over every file request.

Thank you Steven for all the great reference code!

OTHER TIPS

The easy way is to send the contents of a file without sweating mime type detection is to use the static method static ResourceResponse* Awesomium::ResourceResponse::Create.

From the Awesomium docs:

Create a ResourceResponse from a file on disk.

I couldn't figure out a way to map ResourceResponse::Create to DataSource::SendResponse.

As a workaround, you could rewrite your data source as an IResourceInterceptor instead of a DataSource. I wrote up a detailed example in C# on how to use http:// scheme instead of the custom asset:// scheme for embedded resources It should be pretty straightforward to translate the C# to C++. Below is an edited down version of my post (not tested).

using System;
using System.IO;
using System.Reflection;
using Awesomium.Core;

namespace MyApp
{
    public class ResourceInterceptor : IResourceInterceptor
    {
        /// <summary>
        ///     Intercepts any requests for the EmbeddedResourceDomain base Uri,
        ///     and returns a response using the embedded resource in this app's assembly/DLL file
        /// </summary>
        public virtual ResourceResponse OnRequest(ResourceRequest request)
        {
            ResourceResponse response = null;
            string resourceName;
            string filePath;

            filePath = String.Concat("./", request.Url.AbsolutePath);
            filePath = Path.GetFullPath(resourceName.Replace('/', Path.DirectorySeparatorChar));

            // cache the resource to a temp file if 
            if (File.Exists(filePath))
            {
                response = ResourceResponse.Create(filePath);
            }

            return response;
        }

        /// <summary>
        ///     Optionally blocks any web browser requests by returning true.  Not used.
        /// </summary>
        /// <remarks>
        ///     This method can implement a whitelist of allowed URLs here by
        ///     returning true to block any whitelist misses
        /// </remarks>
        public virtual bool OnFilterNavigation(NavigationRequest request)
        {
            return false;
        }
    }
}

Another option might be to hack the HTML content to inject a <base href="file:///c:/my/bin/path" /> element inside the <head> of the document. You would need to modify the href attribute value before loading the content. This may be more work than it is worth.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top