Add support for creating and parsing URLs (issue #181).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@177 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2011-01-31 20:47:04 +00:00
parent 83dd15925f
commit 64d9d8294c
9 changed files with 442 additions and 0 deletions

View File

@ -183,6 +183,7 @@
'tests/unittests/string_unittest.cc', 'tests/unittests/string_unittest.cc',
'tests/unittests/test_handler.h', 'tests/unittests/test_handler.h',
'tests/unittests/test_suite.h', 'tests/unittests/test_suite.h',
'tests/unittests/url_unittest.cc',
'tests/unittests/v8_unittest.cc', 'tests/unittests/v8_unittest.cc',
'tests/unittests/xml_reader_unittest.cc', 'tests/unittests/xml_reader_unittest.cc',
'tests/unittests/zip_reader_unittest.cc', 'tests/unittests/zip_reader_unittest.cc',

View File

@ -59,6 +59,7 @@ class CefSettings;
class CefStreamReader; class CefStreamReader;
class CefStreamWriter; class CefStreamWriter;
class CefTask; class CefTask;
class CefURLParts;
class CefV8Handler; class CefV8Handler;
class CefV8Value; class CefV8Value;
@ -179,6 +180,18 @@ bool CefPostTask(CefThreadId threadId, CefRefPtr<CefTask> task);
bool CefPostDelayedTask(CefThreadId threadId, CefRefPtr<CefTask> task, bool CefPostDelayedTask(CefThreadId threadId, CefRefPtr<CefTask> task,
long delay_ms); long delay_ms);
// Parse the specified |url| into its component parts.
// Returns false if the URL is empty or invalid.
/*--cef()--*/
bool CefParseURL(const CefString& url,
CefURLParts& parts);
// Creates a URL from the specified |parts|, which must contain a non-empty
// spec or a non-empty host and path (at a minimum), but not both.
// Returns false if |parts| isn't initialized as described.
/*--cef()--*/
bool CefCreateURL(const CefURLParts& parts,
CefString& url);
// Interface defining the the reference count implementation methods. All // Interface defining the the reference count implementation methods. All
// framework classes must implement the CefBase class. // framework classes must implement the CefBase class.
@ -1886,4 +1899,77 @@ protected:
} }
}; };
// Class used to represent a URL's component parts.
class CefURLParts : public cef_urlparts_t
{
public:
CefURLParts()
{
Init();
}
virtual ~CefURLParts()
{
Reset();
}
CefURLParts(const CefURLParts& r)
{
Init();
*this = r;
}
CefURLParts(const cef_urlparts_t& r)
{
Init();
*this = r;
}
void Reset()
{
cef_string_clear(&spec);
cef_string_clear(&scheme);
cef_string_clear(&username);
cef_string_clear(&password);
cef_string_clear(&host);
cef_string_clear(&port);
cef_string_clear(&path);
cef_string_clear(&query);
Init();
}
void Attach(const cef_urlparts_t& r)
{
Reset();
*static_cast<cef_urlparts_t*>(this) = r;
}
void Detach()
{
Init();
}
CefURLParts& operator=(const CefURLParts& r)
{
return operator=(static_cast<const cef_urlparts_t&>(r));
}
CefURLParts& operator=(const cef_urlparts_t& r)
{
cef_string_copy(r.spec.str, r.spec.length, &spec);
cef_string_copy(r.scheme.str, r.scheme.length, &scheme);
cef_string_copy(r.username.str, r.username.length, &username);
cef_string_copy(r.password.str, r.password.length, &password);
cef_string_copy(r.host.str, r.host.length, &host);
cef_string_copy(r.port.str, r.port.length, &port);
cef_string_copy(r.path.str, r.path.length, &path);
cef_string_copy(r.query.str, r.query.length, &query);
return *this;
}
protected:
void Init()
{
memset(static_cast<cef_urlparts_t*>(this), 0, sizeof(cef_urlparts_t));
}
};
#endif // _CEF_H #endif // _CEF_H

View File

@ -152,6 +152,17 @@ CEF_EXPORT int cef_post_task(cef_thread_id_t threadId,
CEF_EXPORT int cef_post_delayed_task(cef_thread_id_t threadId, CEF_EXPORT int cef_post_delayed_task(cef_thread_id_t threadId,
struct _cef_task_t* task, long delay_ms); struct _cef_task_t* task, long delay_ms);
// Parse the specified |url| into its component parts. Returns false (0) if the
// URL is NULL or invalid.
CEF_EXPORT int cef_parse_url(const cef_string_t* url,
struct _cef_urlparts_t* parts);
// Creates a URL from the specified |parts|, which must contain a non-NULL spec
// or a non-NULL host and path (at a minimum), but not both. Returns false (0)
// if |parts| isn't initialized as described.
CEF_EXPORT int cef_create_url(const struct _cef_urlparts_t* parts,
cef_string_t* url);
typedef struct _cef_base_t typedef struct _cef_base_t
{ {
// Size of the data structure. // Size of the data structure.

View File

@ -238,6 +238,35 @@ typedef struct _cef_browser_settings_t
bool developer_tools_disabled; bool developer_tools_disabled;
} cef_browser_settings_t; } cef_browser_settings_t;
// URL component parts.
typedef struct _cef_urlparts_t
{
// The complete URL specification.
cef_string_t spec;
// Scheme component not including the colon (e.g., "http").
cef_string_t scheme;
// User name component.
cef_string_t username;
// Password component.
cef_string_t password;
// Host component. This may be a hostname, an IPv4 address or an IPv6 literal
// surrounded by square brackets (e.g., "[2001:db8::1]").
cef_string_t host;
// Port number component.
cef_string_t port;
// Path component including the first slash following the host.
cef_string_t path;
// Query string component (i.e., everything following the '?').
cef_string_t query;
} cef_urlparts_t;
// Define handler return value types. Returning RV_HANDLED indicates // Define handler return value types. Returning RV_HANDLED indicates
// that the implementation completely handled the method and that no further // that the implementation completely handled the method and that no further
// processing is required. Returning RV_CONTINUE indicates that the // processing is required. Returning RV_CONTINUE indicates that the

View File

@ -187,6 +187,69 @@ bool CefPostDelayedTask(CefThreadId threadId, CefRefPtr<CefTask> task,
new CefTaskHelper(task, threadId), delay_ms); new CefTaskHelper(task, threadId), delay_ms);
} }
bool CefParseURL(const CefString& url,
CefURLParts& parts)
{
GURL gurl(url.ToString());
if (!gurl.is_valid())
return false;
CefString(&parts.spec).FromString(gurl.spec());
CefString(&parts.scheme).FromString(gurl.scheme());
CefString(&parts.username).FromString(gurl.username());
CefString(&parts.password).FromString(gurl.password());
CefString(&parts.host).FromString(gurl.host());
CefString(&parts.port).FromString(gurl.port());
CefString(&parts.path).FromString(gurl.path());
CefString(&parts.query).FromString(gurl.query());
return true;
}
bool CefCreateURL(const CefURLParts& parts,
CefString& url)
{
std::string spec = CefString(parts.spec.str, parts.spec.length, false);
std::string scheme = CefString(parts.scheme.str, parts.scheme.length, false);
std::string username =
CefString(parts.username.str, parts.username.length, false);
std::string password =
CefString(parts.password.str, parts.password.length, false);
std::string host = CefString(parts.host.str, parts.host.length, false);
std::string port = CefString(parts.port.str, parts.port.length, false);
std::string path = CefString(parts.path.str, parts.path.length, false);
std::string query = CefString(parts.query.str, parts.query.length, false);
GURL gurl;
if (!spec.empty()) {
gurl = GURL(spec);
} else if (!scheme.empty() && !host.empty()) {
std::stringstream ss;
ss << scheme << "://";
if (!username.empty()) {
ss << username;
if (!password.empty())
ss << ":" << password;
ss << "@";
}
ss << host;
if (!port.empty())
ss << ":" << port;
if (!path.empty())
ss << path;
if (!query.empty())
ss << "?" << query;
gurl = GURL(ss.str());
}
if (gurl.is_valid()) {
url = gurl.spec();
return true;
}
return false;
}
// CefContext // CefContext

View File

@ -186,3 +186,57 @@ CEF_EXPORT int cef_post_delayed_task(cef_thread_id_t threadId,
return CefPostDelayedTask(threadId, CefTaskCToCpp::Wrap(task), delay_ms); return CefPostDelayedTask(threadId, CefTaskCToCpp::Wrap(task), delay_ms);
} }
CEF_EXPORT int cef_parse_url(const cef_string_t* url,
struct _cef_urlparts_t* parts)
{
DCHECK(url && parts);
if(!url || !parts)
return 0;
CefURLParts urlParts;
bool ret = CefParseURL(CefString(url), urlParts);
// Clear the current structure values, if any.
cef_string_clear(&parts->spec);
cef_string_clear(&parts->scheme);
cef_string_clear(&parts->username);
cef_string_clear(&parts->password);
cef_string_clear(&parts->host);
cef_string_clear(&parts->port);
cef_string_clear(&parts->path);
cef_string_clear(&parts->query);
// Transfer ownership of the values from |urlParts| to the structure.
memcpy(parts, static_cast<cef_urlparts_t*>(&urlParts),
sizeof(cef_urlparts_t));
urlParts.Detach();
return ret;
}
CEF_EXPORT int cef_create_url(const struct _cef_urlparts_t* parts,
cef_string_t* url)
{
DCHECK(parts && url);
if(!parts || !url)
return 0;
CefURLParts urlParts;
// Reference the existing structure values without copying.
cef_string_set(parts->spec.str, parts->spec.length, &urlParts.spec, false);
cef_string_set(parts->scheme.str, parts->scheme.length, &urlParts.scheme,
false);
cef_string_set(parts->username.str, parts->username.length,
&urlParts.username, false);
cef_string_set(parts->password.str, parts->password.length,
&urlParts.password, false);
cef_string_set(parts->host.str, parts->host.length, &urlParts.host, false);
cef_string_set(parts->port.str, parts->port.length, &urlParts.port, false);
cef_string_set(parts->path.str, parts->path.length, &urlParts.path, false);
cef_string_set(parts->query.str, parts->query.length, &urlParts.query, false);
CefString urlStr(url);
return CefCreateURL(urlParts, urlStr);
}

View File

@ -159,3 +159,15 @@ bool CefPostDelayedTask(CefThreadId threadId, CefRefPtr<CefTask> task,
return cef_post_delayed_task(threadId, CefTaskCppToC::Wrap(task), delay_ms)? return cef_post_delayed_task(threadId, CefTaskCppToC::Wrap(task), delay_ms)?
true:false; true:false;
} }
bool CefParseURL(const CefString& url,
CefURLParts& parts)
{
return cef_parse_url(url.GetStruct(), &parts) ? true : false;
}
bool CefCreateURL(const CefURLParts& parts,
CefString& url)
{
return cef_create_url(&parts, url.GetWritableStruct()) ? true : false;
}

View File

@ -0,0 +1,185 @@
// 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 "include/cef.h"
#include "testing/gtest/include/gtest/gtest.h"
TEST(URLTest, CreateURL)
{
// Create the URL using the spec.
{
CefURLParts parts;
CefString url;
CefString(&parts.spec).FromASCII(
"http://user:pass@www.example.com:88/path/to.html?foo=test&bar=test2");
ASSERT_TRUE(CefCreateURL(parts, url));
ASSERT_EQ(url,
"http://user:pass@www.example.com:88/path/to.html?foo=test&bar=test2");
}
// Test that scheme and host are required.
{
CefURLParts parts;
CefString url;
CefString(&parts.scheme).FromASCII("http");
ASSERT_FALSE(CefCreateURL(parts, url));
}
{
CefURLParts parts;
CefString url;
CefString(&parts.host).FromASCII("www.example.com");
ASSERT_FALSE(CefCreateURL(parts, url));
}
// Create the URL using scheme and host.
{
CefURLParts parts;
CefString url;
CefString(&parts.scheme).FromASCII("http");
CefString(&parts.host).FromASCII("www.example.com");
ASSERT_TRUE(CefCreateURL(parts, url));
ASSERT_EQ(url, "http://www.example.com/");
}
// Create the URL using scheme, host and path.
{
CefURLParts parts;
CefString url;
CefString(&parts.scheme).FromASCII("http");
CefString(&parts.host).FromASCII("www.example.com");
CefString(&parts.path).FromASCII("/path/to.html");
ASSERT_TRUE(CefCreateURL(parts, url));
ASSERT_EQ(url, "http://www.example.com/path/to.html");
}
// Create the URL using scheme, host, path and query.
{
CefURLParts parts;
CefString url;
CefString(&parts.scheme).FromASCII("http");
CefString(&parts.host).FromASCII("www.example.com");
CefString(&parts.path).FromASCII("/path/to.html");
CefString(&parts.query).FromASCII("foo=test&bar=test2");
ASSERT_TRUE(CefCreateURL(parts, url));
ASSERT_EQ(url, "http://www.example.com/path/to.html?foo=test&bar=test2");
}
// Create the URL using all the various components.
{
CefURLParts parts;
CefString url;
CefString(&parts.scheme).FromASCII("http");
CefString(&parts.username).FromASCII("user");
CefString(&parts.password).FromASCII("pass");
CefString(&parts.host).FromASCII("www.example.com");
CefString(&parts.port).FromASCII("88");
CefString(&parts.path).FromASCII("/path/to.html");
CefString(&parts.query).FromASCII("foo=test&bar=test2");
ASSERT_TRUE(CefCreateURL(parts, url));
ASSERT_EQ(url,
"http://user:pass@www.example.com:88/path/to.html?foo=test&bar=test2");
}
}
TEST(URLTest, ParseURL)
{
// Parse the URL using scheme and host.
{
CefURLParts parts;
CefString url;
url.FromASCII("http://www.example.com");
ASSERT_TRUE(CefParseURL(url, parts));
CefString spec(&parts.spec);
ASSERT_EQ(spec, "http://www.example.com/");
ASSERT_EQ(parts.username.length, 0);
ASSERT_EQ(parts.password.length, 0);
CefString scheme(&parts.scheme);
ASSERT_EQ(scheme, "http");
CefString host(&parts.host);
ASSERT_EQ(host, "www.example.com");
ASSERT_EQ(parts.port.length, 0);
CefString path(&parts.path);
ASSERT_EQ(path, "/");
ASSERT_EQ(parts.query.length, 0);
}
// Parse the URL using scheme, host and path.
{
CefURLParts parts;
CefString url;
url.FromASCII("http://www.example.com/path/to.html");
ASSERT_TRUE(CefParseURL(url, parts));
CefString spec(&parts.spec);
ASSERT_EQ(spec, "http://www.example.com/path/to.html");
ASSERT_EQ(parts.username.length, 0);
ASSERT_EQ(parts.password.length, 0);
CefString scheme(&parts.scheme);
ASSERT_EQ(scheme, "http");
CefString host(&parts.host);
ASSERT_EQ(host, "www.example.com");
ASSERT_EQ(parts.port.length, 0);
CefString path(&parts.path);
ASSERT_EQ(path, "/path/to.html");
ASSERT_EQ(parts.query.length, 0);
}
// Parse the URL using scheme, host, path and query.
{
CefURLParts parts;
CefString url;
url.FromASCII("http://www.example.com/path/to.html?foo=test&bar=test2");
ASSERT_TRUE(CefParseURL(url, parts));
CefString spec(&parts.spec);
ASSERT_EQ(spec, "http://www.example.com/path/to.html?foo=test&bar=test2");
ASSERT_EQ(parts.username.length, 0);
ASSERT_EQ(parts.password.length, 0);
CefString scheme(&parts.scheme);
ASSERT_EQ(scheme, "http");
CefString host(&parts.host);
ASSERT_EQ(host, "www.example.com");
ASSERT_EQ(parts.port.length, 0);
CefString path(&parts.path);
ASSERT_EQ(path, "/path/to.html");
CefString query(&parts.query);
ASSERT_EQ(query, "foo=test&bar=test2");
}
// Parse the URL using all the various components.
{
CefURLParts parts;
CefString url;
url.FromASCII(
"http://user:pass@www.example.com:88/path/to.html?foo=test&bar=test2");
ASSERT_TRUE(CefParseURL(url, parts));
CefString spec(&parts.spec);
ASSERT_EQ(spec,
"http://user:pass@www.example.com:88/path/to.html?foo=test&bar=test2");
CefString scheme(&parts.scheme);
ASSERT_EQ(scheme, "http");
CefString username(&parts.username);
ASSERT_EQ(username, "user");
CefString password(&parts.password);
ASSERT_EQ(password, "pass");
CefString host(&parts.host);
ASSERT_EQ(host, "www.example.com");
CefString port(&parts.port);
ASSERT_EQ(port, "88");
CefString path(&parts.path);
ASSERT_EQ(path, "/path/to.html");
CefString query(&parts.query);
ASSERT_EQ(query, "foo=test&bar=test2");
}
// Parse an invalid URL.
{
CefURLParts parts;
CefString url;
url.FromASCII("www.example.com");
ASSERT_FALSE(CefParseURL(url, parts));
}
}

View File

@ -1060,6 +1060,7 @@ class obj_analysis:
'CefPopupFeatures' : 'cef_popup_features_t', 'CefPopupFeatures' : 'cef_popup_features_t',
'CefSettings' : 'cef_settings_t', 'CefSettings' : 'cef_settings_t',
'CefBrowserSettings' : 'cef_browser_settings_t', 'CefBrowserSettings' : 'cef_browser_settings_t',
'CefURLParts' : 'cef_urlparts_t',
} }
if value in structuretypes.keys(): if value in structuretypes.keys():
return { return {