[ilovegom commit] r64 - in trunk/gom: . include/gom src/gom src/libgom

0 views
Skip to first unread message

codesite...@google.com

unread,
Jul 26, 2008, 3:44:31 PM7/26/08
to gom-c...@googlegroups.com
Author: ja...@87k.net
Date: Sat Jul 26 12:43:10 2008
New Revision: 64

Added:
trunk/gom/cppflags.py
trunk/gom/include/gom/gomuri.h
trunk/gom/ldflags.py
trunk/gom/src/libgom/gomuri.c
Modified:
trunk/gom/ChangeLog
trunk/gom/configure.ac
trunk/gom/include/gom/Makefile.inc
trunk/gom/src/gom/Makefile.inc
trunk/gom/src/gom/gom.c
trunk/gom/src/libgom/Makefile.inc
trunk/gom/src/libgom/gomdoc.c
trunk/gom/src/libgom/gomdominterfaces.c
trunk/gom/src/libgom/gomjswindow.c
trunk/gom/src/libgom/gomjsxmlhttprequest.c
trunk/gom/src/libgom/gomxhr.c

Log:
2008-07-26 jacob berkman <ja...@ilovegom.org>

* src/libgom/gomdominterfaces.c:
* src/libgom/gomdoc.c (gom_doc_get_property)
(gom_doc_set_property): add documentURI level 3 property

* src/libgom/gomjswindow.c
(gom_js_window_parser_start_element): create a document
manually, that is without using the standard DOM api, so we
can pass in the document's uri
(gom_js_window_parser_end_element): use GomURI to resolve
relative hrefs
(gom_js_window_parse_file): use GomURI to resolve relative
paths

* src/libgom/gomxhr.c (gom_xhr_get_property): impl for readyState
(gom_xhr_set_property): impl for document
(is_token): determine if something is an HTTP token
(gom_xhr_open): begin implementation
(is_lws): determine if something is http leading whitespace
(is_quoted_string, is_value): more http rfc checks
(gom_xhr_set_request_header): implement

* src/libgom/gomjsxmlhttprequest.c (gom_js_xml_http_request_open)
(gom_js_xml_http_request_set_request_header)
(gom_js_xml_http_request_send)
(gom_js_xml_http_request_abort)
(gom_js_xml_http_request_get_all_response_headers)
(gom_js_xml_http_request_get_response_header): implement binding
(gom_js_xml_http_request_construct): set the appropriate
document object when constructing

* cppflags.py:
* ldflags.py: detect python build options

* src/libgom/gomuri.c: new object for manipulating uris

Modified: trunk/gom/ChangeLog
==============================================================================
--- trunk/gom/ChangeLog (original)
+++ trunk/gom/ChangeLog Sat Jul 26 12:43:10 2008
@@ -1,3 +1,40 @@
+2008-07-26 jacob berkman <ja...@ilovegom.org>
+
+ * src/libgom/gomdominterfaces.c:
+ * src/libgom/gomdoc.c (gom_doc_get_property)
+ (gom_doc_set_property): add documentURI level 3 property
+
+ * src/libgom/gomjswindow.c
+ (gom_js_window_parser_start_element): create a document
+ manually, that is without using the standard DOM api, so we
+ can pass in the document's uri
+ (gom_js_window_parser_end_element): use GomURI to resolve
+ relative hrefs
+ (gom_js_window_parse_file): use GomURI to resolve relative
+ paths
+
+ * src/libgom/gomxhr.c (gom_xhr_get_property): impl for readyState
+ (gom_xhr_set_property): impl for document
+ (is_token): determine if something is an HTTP token
+ (gom_xhr_open): begin implementation
+ (is_lws): determine if something is http leading whitespace
+ (is_quoted_string, is_value): more http rfc checks
+ (gom_xhr_set_request_header): implement
+
+ * src/libgom/gomjsxmlhttprequest.c (gom_js_xml_http_request_open)
+ (gom_js_xml_http_request_set_request_header)
+ (gom_js_xml_http_request_send)
+ (gom_js_xml_http_request_abort)
+ (gom_js_xml_http_request_get_all_response_headers)
+ (gom_js_xml_http_request_get_response_header): implement binding
+ (gom_js_xml_http_request_construct): set the appropriate
+ document object when constructing
+
+ * cppflags.py:
+ * ldflags.py: detect python build options
+
+ * src/libgom/gomuri.c: new object for manipulating uris
+
2008-07-20 jacob berkman <ja...@ilovegom.org>

* src/libgom/gomgcmanager.c: remove GomGCManaged interface

Modified: trunk/gom/configure.ac
==============================================================================
--- trunk/gom/configure.ac (original)
+++ trunk/gom/configure.ac Sat Jul 26 12:43:10 2008
@@ -13,6 +13,7 @@
# Checks for packages
GLIB_REQVER="2.6.0"
GTK_REQVER="2.6.0"
+CURL_REQVER="0"

GOM_MODULES="gtk+-2.0 >= $GTK_REQVER gthread-2.0"
PKG_CHECK_MODULES(GOM, [$GOM_MODULES])
@@ -103,6 +104,10 @@
AC_SUBST(JS_LIBS, ["$mozilla_source/$moz_objdir/libjs.a $moz_oslibs"])
AC_SUBST(DISTCHECK_CONFIGURE_FLAGS,["--with-mozilla-source=$mozilla_source"])

+AC_SUBST(PY_LDFLAGS,[$(python ldflags.py)])
+AC_SUBST(PY_CPPFLAGS,[$(python cppflags.py)])
+AC_SUBST(CURL_CFLAGS,[$(pkg-config --cflags libcurl)])
+AC_SUBST(CURL_LIBS,[$(pkg-config --libs-only-L --libs-only-l libcurl)])
# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

Added: trunk/gom/cppflags.py
==============================================================================
--- (empty file)
+++ trunk/gom/cppflags.py Sat Jul 26 12:43:10 2008
@@ -0,0 +1,2 @@
+import distutils.sysconfig
+print '-I%s' % distutils.sysconfig.get_python_inc()

Modified: trunk/gom/include/gom/Makefile.inc
==============================================================================
--- trunk/gom/include/gom/Makefile.inc (original)
+++ trunk/gom/include/gom/Makefile.inc Sat Jul 26 12:43:10 2008
@@ -40,6 +40,7 @@
include/gom/gomobject.h \
include/gom/gomtxt.h \
include/gom/gomuievt.h \
+ include/gom/gomuri.h \
include/gom/gomvalue.h \
include/gom/gomwidget.h \
include/gom/gomxhr.h

Added: trunk/gom/include/gom/gomuri.h
==============================================================================
--- (empty file)
+++ trunk/gom/include/gom/gomuri.h Sat Jul 26 12:43:10 2008
@@ -0,0 +1,62 @@
+/*
+The MIT License
+
+Copyright (c) 2008 jacob berkman <ja...@ilovegom.org>
+
+Permission is hereby granted, free of charge, to any person obtaining
a copy
+of this software and associated documentation files (the "Software"),
to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#ifndef GOM_URI_H
+#define GOM_URI_H
+
+#include <glib/gmacros.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GomURI GomURI;
+typedef struct _GomURIClass GomURIClass;
+
+G_END_DECLS
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GOM_TYPE_URI (gom_uri_get_type ())
+#define GOM_URI(i) (G_TYPE_CHECK_INSTANCE_CAST ((i),
GOM_TYPE_URI, GomURI))
+#define GOM_URI_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k),
GOM_TYPE_URI, GomURIClass))
+#define GOM_IS_URI(i) (G_TYPE_CHECK_INSTANCE_TYPE ((i), GOM_TYPE_URI))
+#define GOM_IS_URI_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOM_TYPE_URI))
+#define GOM_URI_GET_CLASS(i) (G_TYPE_INSTANCE_GET_CLASS ((i),
GOM_TYPE_URI, GomURIClass))
+
+struct _GomURI {
+ GObject parent;
+};
+
+struct _GomURIClass {
+ GObjectClass parent_class;
+};
+
+GType gom_uri_get_type (void);
+
+char *gom_uri_join (const char *base_uri, const char *relative_uri);
+gboolean gom_uri_is_relative (const GomURI *uri);
+
+G_END_DECLS
+
+#endif /* GOM_URI_H */

Added: trunk/gom/ldflags.py
==============================================================================
--- (empty file)
+++ trunk/gom/ldflags.py Sat Jul 26 12:43:10 2008
@@ -0,0 +1,2 @@
+import distutils.sysconfig
+print distutils.sysconfig.get_config_var('LINKFORSHARED')

Modified: trunk/gom/src/gom/Makefile.inc
==============================================================================
--- trunk/gom/src/gom/Makefile.inc (original)
+++ trunk/gom/src/gom/Makefile.inc Sat Jul 26 12:43:10 2008
@@ -3,5 +3,5 @@
bin_PROGRAMS += gom

gom_SOURCES := src/gom/gom.c
-gom_CFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
$(GOM_CFLAGS) $(JS_CFLAGS)
-gom_LDADD := libgom.la $(GOM_LIBS) $(JS_LIBS)
+gom_CFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
$(GOM_CFLAGS) $(JS_CFLAGS) $(PY_CPPFLAGS)
+gom_LDADD := $(PY_LDFLAGS) libgom.la $(GOM_LIBS) $(JS_LIBS) $(CURL_LIBS)

Modified: trunk/gom/src/gom/gom.c
==============================================================================
--- trunk/gom/src/gom/gom.c (original)
+++ trunk/gom/src/gom/gom.c Sat Jul 26 12:43:10 2008
@@ -36,7 +36,7 @@
static void
gom_error_reporter (JSContext *cx, const char *message, JSErrorReport *report)
{
- g_warning (G_STRLOC"%s:%d: Unhandled JavaScript exception: %s (%d)\n",
+ g_warning (G_STRLOC": %s:%d: Unhandled JavaScript exception: %s (%d)\n",
report->filename, report->lineno,
message, report->errorNumber);
}

Modified: trunk/gom/src/libgom/Makefile.inc
==============================================================================
--- trunk/gom/src/libgom/Makefile.inc (original)
+++ trunk/gom/src/libgom/Makefile.inc Sat Jul 26 12:43:10 2008
@@ -41,12 +41,13 @@
src/libgom/gomobject.c \
src/libgom/gomtxt.c \
src/libgom/gomuievt.c \
+ src/libgom/gomuri.c \
src/libgom/gomvalue.c \
src/libgom/gomwidget.c \
src/libgom/gomxhr.c

-libgom_la_CFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
$(GOM_CFLAGS) $(JS_CFLAGS)
-libgom_la_LDFLAGS = $(GOM_LIBS)
+libgom_la_CFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
$(GOM_CFLAGS) $(JS_CFLAGS) $(PY_CPPFLAGS) $(CURL_CFLAGS)
+libgom_la_LDFLAGS = $(PY_LDFLAGS) $(GOM_LIBS) $(CURL_LIBS)

src/libgom/gomdominterfaces.c: include/gom/dom/gomdombuiltins.h


Modified: trunk/gom/src/libgom/gomdoc.c
==============================================================================
--- trunk/gom/src/libgom/gomdoc.c (original)
+++ trunk/gom/src/libgom/gomdoc.c Sat Jul 26 12:43:10 2008
@@ -53,13 +53,15 @@
PROP_IMPLEMENTATION,
PROP_DOCUMENT_ELEMENT,
PROP_NODE_NAME,
- PROP_NODE_TYPE
+ PROP_NODE_TYPE,
+ PROP_DOCUMENT_URI
};

typedef struct {
GomDOMImplementation *implementation;
GomDocumentType *doctype;
guint constructed : 1;
+ const char *document_uri;
} GomDocPrivate;

#define PRIV(o) G_TYPE_INSTANCE_GET_PRIVATE ((o), GOM_TYPE_DOC, GomDocPrivate)
@@ -94,6 +96,9 @@
case PROP_NODE_TYPE:
g_value_set_enum (value, GOM_DOCUMENT_NODE);
break;
+ case PROP_DOCUMENT_URI:
+ g_value_set_string (value, priv->document_uri);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -115,6 +120,9 @@
case PROP_IMPLEMENTATION:
priv->implementation = g_value_dup_object (value);
return;
+ case PROP_DOCUMENT_URI:
+ priv->document_uri = g_value_dup_string (value);
+ return;
}
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -607,4 +615,5 @@
g_object_class_override_property (oclass, PROP_DOCUMENT_ELEMENT, "document-element");
g_object_class_override_property (oclass, PROP_NODE_NAME, "node-name");
g_object_class_override_property (oclass, PROP_NODE_TYPE, "node-type");
+ g_object_class_override_property (oclass, PROP_DOCUMENT_URI, "document-u-r-i");
}

Modified: trunk/gom/src/libgom/gomdominterfaces.c
==============================================================================
--- trunk/gom/src/libgom/gomdominterfaces.c (original)
+++ trunk/gom/src/libgom/gomdominterfaces.c Sat Jul 26 12:43:10 2008
@@ -164,6 +164,15 @@
"This is a convenience attribute that
allows direct access to the child node that is the root element of the document.",
GOM_TYPE_ELEMENT,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+ /* DOM Level 3 */
+ g_object_interface_install_property (
+ g_iface,
+ g_param_spec_string ("document-u-r-i", NULL,
+ "The location of the document or null if
undefined or if the Document was created using DOMImplementation.createDocument.",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
}, GOM_TYPE_NODE);

GOM_STUB_FUNC (GOM_DOCUMENT, gom_document, create_element,

Modified: trunk/gom/src/libgom/gomjswindow.c
==============================================================================
--- trunk/gom/src/libgom/gomjswindow.c (original)
+++ trunk/gom/src/libgom/gomjswindow.c Sat Jul 26 12:43:10 2008
@@ -29,11 +29,13 @@
#include "gom/dom/gomdocumentevent.h"
#include "gom/dom/gomdomimplementation.h"
#include "gom/dom/gomeventtarget.h"
+#include "gom/gomdoc.h"
#include "gom/gomdom.h"
#include "gom/gomjscontext.h"
#include "gom/gomjsexception.h"
#include "gom/gomjsobject.h"
#include "gom/gomobject.h"
+#include "gom/gomuri.h"

#include "gommacros.h"

@@ -317,7 +319,7 @@
};

typedef struct {
- const char *filename;
+ char *filename;
JSContext *cx;
JSObject *window;
GomDocument *doc;
@@ -426,16 +428,29 @@

if (!data->doc) {
GomDOMImplementation *dom;
+
dom = g_object_new (GOM_TYPE_DOM, NULL);
- data->doc = gom_dom_implementation_create_document (dom,
namespace, element_name, NULL, error);
- g_object_unref (dom);
- if (data->doc) {
- data->jsdoc = gom_js_object_get_or_create_js_object
(data->cx, data->doc);
- JS_DefineProperty (data->cx, data->window, "document",
- OBJECT_TO_JSVAL (data->jsdoc), NULL, NULL,
- JSPROP_PERMANENT | JSPROP_READONLY);
- g_object_get (data->doc, "document-element",
&data->scope->elem, NULL);
+ data->doc = g_object_new (GOM_TYPE_DOC,
+ "doctype", NULL,
+ "implementation", dom,
+ "document-u-r-i", data->filename,
+ NULL);
+ g_object_unref (dom);
+
+ data->scope->elem = gom_document_create_element_ns (data->doc,
namespace, element_name, error);
+ if (data->scope->elem) {
+ gom_node_append_child (GOM_NODE (data->doc), GOM_NODE
(data->scope->elem), error);
+ }
+ if (!data->scope->elem || *error) {
+ pop_scope (data);
+ g_object_unref (data->doc);
+ data->doc = NULL;
+ return;
}
+ data->jsdoc = gom_js_object_get_or_create_js_object (data->cx, data->doc);
+ JS_DefineProperty (data->cx, data->window, "document",
+ OBJECT_TO_JSVAL (data->jsdoc), NULL, NULL,
+ JSPROP_PERMANENT | JSPROP_READONLY);
} else {
data->scope->elem = gom_document_create_element_ns (data->doc,
namespace, element_name, error);
}
@@ -533,17 +548,26 @@
*/
file = gom_element_get_attribute (data->scope->elem, "src");
if (file) {
- if (!g_path_is_absolute (file)) {
- char *dir = g_path_get_dirname (data->filename);
- char *f2 = g_build_filename (dir, file, NULL);
- g_free (file);
- g_free (dir);
- file = f2;
- }
- if (!g_file_get_contents (file, &script, &script_len,
&err)) {
- g_printerr (G_STRLOC": could not load %s: %s\n",
- file, err->message);
- g_error_free (err);
+ char *f2;
+ f2 = gom_uri_join (data->filename, file);
+ if (!f2) {
+ g_printerr (G_STRLOC": could not resolve relative
filename %s\n", file);
+ } else {
+ GomURI *uri;
+ char *scheme;
+ uri = g_object_new (GOM_TYPE_URI, "uri", f2, NULL);
+ g_free (f2);
+ g_object_get (uri, "scheme", &scheme, "path", &f2, NULL);
+ g_object_unref (uri);
+ if (!strcmp (scheme, "file")) {
+ g_free (file);
+ file = f2;
+ }
+ if (!g_file_get_contents (file, &script, &script_len,
&err)) {
+ g_printerr (G_STRLOC": could not load %s: %s\n",
+ file, err->message);
+ g_error_free (err);
+ }
}
filename = file;
lineno = 0;
@@ -579,7 +603,7 @@
script, script_len,
filename, lineno, &rval)) {
if (!gom_js_exception_get_error (data->cx, &err)) {
- g_set_error (error, GOM_JS_ERROR, GOM_JS_ERROR_UNKNOWN,
+ g_set_error (&err, GOM_JS_ERROR, GOM_JS_ERROR_UNKNOWN,
"Unknown error encountered while
running script at %s:%d\n",
data->filename, lineno);
}
@@ -649,7 +673,19 @@
goto out;
}

- data.filename = filename;
+ if (g_path_is_absolute (filename)) {
+ data.filename = g_strdup_printf ("file://%s", filename);
+ } else {
+ char *base;
+ char *pwd;
+
+ pwd = g_get_current_dir ();
+ base = g_strdup_printf ("file://%s/", pwd);
+ g_free (pwd);
+
+ data.filename = gom_uri_join (base, filename);
+ g_free (base);
+ }
data.cx = cx;
data.window = window;

@@ -660,6 +696,7 @@
g_markup_parse_context_end_parse (ctx, &error);
}
g_markup_parse_context_free (ctx);
+ g_free (data.filename);
g_free (xml);
if (data.doc) {
g_object_unref (data.doc);

Modified: trunk/gom/src/libgom/gomjsxmlhttprequest.c
==============================================================================
--- trunk/gom/src/libgom/gomjsxmlhttprequest.c (original)
+++ trunk/gom/src/libgom/gomjsxmlhttprequest.c Sat Jul 26 12:43:10 2008
@@ -60,43 +60,160 @@
static JSBool
gom_js_xml_http_request_open (JSContext *cx, JSObject *obj, uintN
argc, jsval *argv, jsval *rval)
{
- GOM_JS_NOT_IMPLEMENTED (cx);
- return JS_FALSE;
+ GomXMLHttpRequest *req;
+ char *method;
+ char *url;
+ JSBool async;
+ char *user;
+ char *password;
+ GError *error = NULL;
+
+ req = gom_js_object_get_g_object (cx, obj);
+ if (!GOM_IS_XML_HTTP_REQUEST (req)) {
+ return JS_FALSE;
+ }
+ if (!JS_ConvertArguments (cx, argc, argv, "ss/bss",
+ &method, &url, &async,
+ &user, &password)) {
+ return JS_FALSE;
+ }
+
+ gom_xml_http_request_open (req, method, url,
+ argc >= 3 ? async ? TRUE : FALSE : TRUE,
+ argc >= 4 ? user : GOM_XML_HTTP_REQUEST_OMITTED,
+ argc >= 5 ? password : GOM_XML_HTTP_REQUEST_OMITTED,
+ &error);
+ if (error) {
+ return gom_js_exception_set_error (cx, &error);
+ }
+
+ return JS_TRUE;
}

static JSBool
gom_js_xml_http_request_set_request_header (JSContext *cx, JSObject
*obj, uintN argc, jsval *argv, jsval *rval)
{
- GOM_JS_NOT_IMPLEMENTED (cx);
- return JS_FALSE;
+ GomXMLHttpRequest *req;
+ char *name;
+ char *value;
+ GError *error = NULL;
+
+ req = gom_js_object_get_g_object (cx, obj);
+ if (!GOM_IS_XML_HTTP_REQUEST (req)) {
+ return JS_FALSE;
+ }
+ if (!JS_ConvertArguments (cx, argc, argv, "ss", &name, &value)) {
+ return JS_FALSE;
+ }
+
+ gom_xml_http_request_set_request_header (req, name, value, &error);
+ if (error) {
+ return gom_js_exception_set_error (cx, &error);
+ }
+
+ return JS_TRUE;
}

static JSBool
gom_js_xml_http_request_send (JSContext *cx, JSObject *obj, uintN
argc, jsval *argv, jsval *rval)
{
- GOM_JS_NOT_IMPLEMENTED (cx);
- return JS_FALSE;
+ GomXMLHttpRequest *req;
+ GError *error = NULL;
+ char *data;
+ JSObject *jsdoc;
+ GomDocument *doc;
+
+ req = gom_js_object_get_g_object (cx, obj);
+ if (!GOM_IS_XML_HTTP_REQUEST (req)) {
+ return JS_FALSE;
+ }
+
+ if (argc == 0) {
+ gom_xml_http_request_send (req, &error);
+ } else if (JSVAL_IS_STRING (argv[0]) &&
+ JS_ConvertArguments (cx, argc, argv, "s", &data)) {
+ gom_xml_http_request_send_string (req, data, &error);
+ } else if (JSVAL_IS_OBJECT (argv[0]) &&
+ JS_ConvertArguments (cx, argc, argv, "o", &jsdoc)) {
+ doc = gom_js_object_get_g_object (cx, obj);
+ if (!GOM_IS_DOCUMENT (doc)) {
+ return JS_FALSE;
+ }
+ gom_xml_http_request_send_document (req, doc, &error);
+ }
+ if (error) {
+ return gom_js_exception_set_error (cx, &error);
+ }
+ return JS_TRUE;
}

static JSBool
gom_js_xml_http_request_abort (JSContext *cx, JSObject *obj, uintN
argc, jsval *argv, jsval *rval)
{
- GOM_JS_NOT_IMPLEMENTED (cx);
- return JS_FALSE;
+ GomXMLHttpRequest *req;
+
+ req = gom_js_object_get_g_object (cx, obj);
+ if (!GOM_IS_XML_HTTP_REQUEST (req)) {
+ return JS_FALSE;
+ }
+ if (argc != 0) {
+ return JS_FALSE;
+ }
+
+ gom_xml_http_request_abort (req);
+
+ return JS_TRUE;
}

static JSBool
gom_js_xml_http_request_get_all_response_headers (JSContext *cx,
JSObject *obj, uintN argc, jsval *argv, jsval *rval)
{
- GOM_JS_NOT_IMPLEMENTED (cx);
- return JS_FALSE;
+ GomXMLHttpRequest *req;
+ GError *error = NULL;
+ char *headers;
+
+ req = gom_js_object_get_g_object (cx, obj);
+ if (!GOM_IS_XML_HTTP_REQUEST (req)) {
+ return JS_FALSE;
+ }
+ if (argc != 0) {
+ return JS_FALSE;
+ }
+
+ headers = gom_xml_http_request_get_all_response_headers (req, &error);
+ if (error) {
+ return gom_js_exception_set_error (cx, &error);
+ }
+
+ *rval = STRING_TO_JSVAL (JS_NewStringCopyZ (cx, headers));
+
+ return JS_TRUE;
}

static JSBool
gom_js_xml_http_request_get_response_header (JSContext *cx, JSObject
*obj, uintN argc, jsval *argv, jsval *rval)
{
- GOM_JS_NOT_IMPLEMENTED (cx);
- return JS_FALSE;
+ GomXMLHttpRequest *req;
+ char *header;
+ GError *error = NULL;
+
+ req = gom_js_object_get_g_object (cx, obj);
+ if (!GOM_IS_XML_HTTP_REQUEST (req)) {
+ return JS_FALSE;
+ }
+ if (!JS_ConvertArguments (cx, argc, argv, "s", &header)) {
+ return JS_FALSE;
+ }
+
+ /* the passed-in header belongs to the JS runtime; no need to free */
+ header = gom_xml_http_request_get_response_header (req, header, &error);
+ if (error) {
+ return gom_js_exception_set_error (cx, &error);
+ }
+
+ *rval = STRING_TO_JSVAL (JS_NewStringCopyZ (cx, header));
+
+ return JS_TRUE;
}

static JSFunctionSpec gom_js_xml_http_request_funcs[] = {
@@ -112,9 +229,27 @@
static JSBool
gom_js_xml_http_request_construct (JSContext *cx, JSObject *obj, uintN
argc, jsval *argv, jsval *rval)
{
- GObject *gobj = g_object_new (GOM_TYPE_XHR, NULL);
+ JSObject *win;
+ GObject *gobj;
+ GomDocument *doc;
+ jsval jsdoc;
+
+ win = JS_GetPrototype (cx, obj);
+ if (win) {
+ win = JS_GetParent (cx, win);
+ }
+ if (!win ||
+ !JS_LookupProperty (cx, win, "document", &jsdoc) ||
+ !JSVAL_IS_OBJECT (jsdoc)) {
+ return JS_FALSE;
+ }
+
+ doc = gom_js_object_get_g_object (cx, JSVAL_TO_OBJECT (jsdoc));
+
+ gobj = g_object_new (GOM_TYPE_XHR, "document", doc, NULL);
gom_js_object_set_g_object (cx, obj, gobj);
g_object_unref (gobj);
+
return JS_TRUE;
}


Added: trunk/gom/src/libgom/gomuri.c
==============================================================================
--- (empty file)
+++ trunk/gom/src/libgom/gomuri.c Sat Jul 26 12:43:10 2008
@@ -0,0 +1,476 @@
+/*
+The MIT License
+
+Copyright (c) 2008 jacob berkman <ja...@ilovegom.org>
+
+Permission is hereby granted, free of charge, to any person obtaining
a copy
+of this software and associated documentation files (the "Software"),
to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <Python.h>
+
+#include "config.h"
+
+#include "gom/gomuri.h"
+
+enum {
+ PROP_URI = 1,
+ PROP_SCHEME,
+ PROP_NETLOC,
+ PROP_PATH,
+ PROP_QUERY,
+ PROP_FRAGMENT,
+ PROP_USERNAME,
+ PROP_PASSWORD,
+ PROP_HOSTNAME,
+ PROP_PORT
+};
+
+typedef struct {
+ char *uri;
+ char *scheme;
+ char *netloc;
+ char *path;
+ char *query;
+ char *fragment;
+ char *username;
+ char *password;
+ char *hostname;
+ int port;
+} GomURIPrivate;
+
+static PyObject *urlsplit = NULL;
+static PyObject *urlunsplit = NULL;
+static PyObject *urljoin = NULL;
+static PyObject *urldefrag = NULL;
+
+#define PRIV(i) G_TYPE_INSTANCE_GET_PRIVATE ((i), GOM_TYPE_URI, GomURIPrivate)
+
+static gpointer
+init_python_once (gpointer data)
+{
+ PyObject *name;
+ PyObject *mod;
+
+ Py_Initialize();
+
+ name = PyString_FromString ("urlparse");
+ mod = PyImport_Import (name);
+ Py_DECREF (name);
+
+ if (!mod) {
+ PyErr_Print ();
+ g_warning (G_STRLOC": could not load urlparse module");
+ return NULL;
+ }
+
+#define GET_FUNC(f) \
+ f = PyObject_GetAttrString (mod, #f); \
+ if (!f || !PyCallable_Check (f)) { \
+ if (PyErr_Occurred ()) { \
+ PyErr_Print (); \
+ } \
+ g_warning (G_STRLOC": could not look up "#f); \
+ }
+
+ GET_FUNC (urlsplit);
+ GET_FUNC (urlunsplit);
+ GET_FUNC (urljoin);
+ GET_FUNC (urldefrag);
+
+ Py_DECREF (mod);
+
+ return NULL;
+}
+
+static void
+init_python (void)
+{
+ static GOnce python_once = G_ONCE_INIT;
+ g_once (&python_once, init_python_once, NULL);
+}
+
+gboolean
+gom_uri_is_relative (const GomURI *uri)
+{
+ GomURIPrivate *priv = PRIV (uri);
+ return *priv->scheme && *priv->netloc && *priv->path == '/';
+}
+
+char *
+gom_uri_join (const char *base_uri, const char *relative_uri)
+{
+ PyObject *args;
+ PyObject *ret;
+ char *new_uri;
+
+ init_python ();
+
+ args = PyTuple_New (2);
+ PyTuple_SetItem (args, 0, PyString_FromString (base_uri));
+ PyTuple_SetItem (args, 1, PyString_FromString (relative_uri));
+
+ ret = PyObject_CallObject (urljoin, args);
+ Py_DECREF (args);
+ if (!ret) {
+ PyErr_Print ();
+ g_warning (G_STRLOC": urljoin(%s, %s) failed", base_uri, relative_uri);
+ return NULL;
+ }
+
+ new_uri = g_strdup (PyString_AsString (ret));
+ Py_DECREF (ret);
+ return new_uri;
+}
+
+static void
+gom_uri_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GomURIPrivate *priv = PRIV (object);
+ switch (property_id) {
+ case PROP_URI:
+ g_value_set_string (value, priv->uri);
+ break;
+ case PROP_SCHEME:
+ g_value_set_string (value, priv->scheme);
+ break;
+ case PROP_NETLOC:
+ g_value_set_string (value, priv->netloc);
+ break;
+ case PROP_PATH:
+ g_value_set_string (value, priv->path);
+ break;
+ case PROP_QUERY:
+ g_value_set_string (value, priv->query);
+ break;
+ case PROP_FRAGMENT:
+ g_value_set_string (value, priv->fragment);
+ break;
+ case PROP_USERNAME:
+ g_value_set_string (value, priv->username);
+ break;
+ case PROP_PASSWORD:
+ g_value_set_string (value, priv->password);
+ break;
+ case PROP_HOSTNAME:
+ g_value_set_string (value, priv->hostname);
+ break;
+ case PROP_PORT:
+ g_value_set_int (value, priv->port);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+free_and_xxx (char *s)
+{
+ char *c;
+ if (!s) {
+ return;
+ }
+ for (c = s; *c; c++) {
+ *c = 'X';
+ }
+ g_free (s);
+}
+
+static void
+free_priv (GomURIPrivate *priv)
+{
+ free_and_xxx (priv->uri);
+ g_free (priv->scheme);
+ free_and_xxx (priv->netloc);
+ g_free (priv->path);
+ g_free (priv->query);
+ g_free (priv->fragment);
+ g_free (priv->username);
+ free_and_xxx (priv->password);
+ g_free (priv->hostname);
+ memset (priv, 0, sizeof (GomURIPrivate));
+}
+
+static void
+uri_split (GomURI *uri, const char *new_uri)
+{
+ GomURIPrivate *priv = PRIV (uri);
+ PyObject *args;
+ PyObject *ret;
+ PyObject *val;
+
+ free_priv (priv);
+
+ args = PyTuple_New (1);
+ PyTuple_SetItem (args, 0, PyString_FromString (new_uri));
+
+ ret = PyObject_CallObject (urlsplit, args);
+ Py_DECREF (args);
+ if (!ret) {
+ PyErr_Print ();
+ g_warning (G_STRLOC": urlsplit(%s) failed", new_uri);
+ return;
+ }
+
+ priv->uri = g_strdup (new_uri);
+
+#define GET_ATTR(a) \
+ val = PyObject_GetAttrString (ret, #a); \
+ if (val) { \
+ priv->a = g_strdup (PyString_AsString (val)); \
+ Py_DECREF (val); \
+ }
+
+ GET_ATTR(scheme);
+ GET_ATTR(netloc);
+ GET_ATTR(path);
+ GET_ATTR(query);
+ GET_ATTR(fragment);
+ GET_ATTR(username);
+ GET_ATTR(password);
+ GET_ATTR(hostname);
+
+#undef GET_ATTR
+
+ val = PyObject_GetAttrString (ret, "port");
+ priv->port = PyInt_AsLong (val);
+ Py_DECREF (val);
+
+ Py_DECREF (args);
+ Py_DECREF (ret);
+}
+
+static void
+uri_unsplit (GomURI *uri)
+{
+ GomURIPrivate *priv = PRIV (uri);
+ PyObject *tuple;
+ PyObject *args;
+ PyObject *ret;
+
+ tuple = PyTuple_New (5);
+ PyTuple_SetItem (tuple, 0, PyString_FromString (priv->scheme ?
priv->scheme : ""));
+ PyTuple_SetItem (tuple, 1, PyString_FromString (priv->netloc ?
priv->netloc : ""));
+ PyTuple_SetItem (tuple, 2, PyString_FromString (priv->path ?
priv->path : ""));
+ PyTuple_SetItem (tuple, 3, PyString_FromString (priv->query ?
priv->query : ""));
+ PyTuple_SetItem (tuple, 4, PyString_FromString (priv->fragment ? priv->fragment : ""));
+
+ args = PyTuple_New (1);
+ PyTuple_SetItem (args, 0, tuple);
+
+ ret = PyObject_CallObject (urlunsplit, args);
+ Py_DECREF (args);
+ Py_DECREF (tuple);
+ if (!ret) {
+ PyErr_Print ();
+ g_warning (G_STRLOC": urlunsplit(\"%s\", \"%s\", \"%s, \"%s\",
\"%s\") failed\n",
+ priv->scheme, priv->netloc, priv->path,
+ priv->query, priv->fragment);
+ return;
+ }
+
+ uri_split (uri, PyString_AsString (ret));
+
+ Py_DECREF (ret);
+}
+
+static void
+fixup_netloc (GomURI *uri)
+{
+ GomURIPrivate *priv = PRIV (uri);
+ free_and_xxx (priv->netloc);
+
+ GString *str = g_string_new (NULL);
+ if (priv->username) {
+ g_string_append (str, priv->username);
+ if (priv->password) {
+ g_string_append_c (str, ':');
+ g_string_append (str, priv->password);
+ }
+ g_string_append_c (str, '@');
+ }
+ if (priv->hostname) {
+ g_string_append (str, priv->hostname);
+ }
+ g_string_append_c (str, ':');
+ g_string_append_printf (str, "%d", priv->port);
+
+ priv->netloc = g_string_free (str, FALSE);
+
+ uri_unsplit (uri);
+}
+
+static void
+gom_uri_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GomURIPrivate *priv = PRIV (object);
+ switch (property_id) {
+ case PROP_URI:
+ uri_split (GOM_URI (object), g_value_get_string (value));
+ break;
+ case PROP_SCHEME:
+ g_free (priv->scheme);
+ priv->scheme = g_value_dup_string (value);
+ uri_unsplit (GOM_URI (object));
+ break;
+ case PROP_NETLOC:
+ free_and_xxx (priv->netloc);
+ priv->netloc = g_value_dup_string (value);
+ uri_unsplit (GOM_URI (object));
+ break;
+ case PROP_PATH:
+ g_free (priv->path);
+ priv->path = g_value_dup_string (value);
+ uri_unsplit (GOM_URI (object));
+ break;
+ case PROP_QUERY:
+ g_free (priv->query);
+ priv->query = g_value_dup_string (value);
+ uri_unsplit (GOM_URI (object));
+ break;
+ case PROP_FRAGMENT:
+ g_free (priv->fragment);
+ priv->fragment = g_value_dup_string (value);
+ uri_unsplit (GOM_URI (object));
+ break;
+ case PROP_USERNAME:
+ g_free (priv->username);
+ priv->username = g_value_dup_string (value);
+ fixup_netloc (GOM_URI (object));
+ break;
+ case PROP_PASSWORD:
+ free_and_xxx (priv->password);
+ priv->password = g_value_dup_string (value);
+ fixup_netloc (GOM_URI (object));
+ break;
+ case PROP_HOSTNAME:
+ g_free (priv->hostname);
+ priv->hostname = g_value_dup_string (value);
+ fixup_netloc (GOM_URI (object));
+ break;
+ case PROP_PORT:
+ priv->port = g_value_get_int (value);
+ fixup_netloc (GOM_URI (object));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+G_DEFINE_TYPE(GomURI, gom_uri, G_TYPE_OBJECT);
+
+static void gom_uri_init (GomURI *uri) { }
+
+static void
+gom_uri_dispose (GObject *object)
+{
+ free_priv (PRIV (object));
+
+ G_OBJECT_CLASS (gom_uri_parent_class)->dispose (object);
+}
+
+static void
+gom_uri_class_init (GomURIClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+
+ init_python ();
+
+ g_type_class_add_private (klass, sizeof (GomURIPrivate));
+
+ oclass->get_property = gom_uri_get_property;
+ oclass->set_property = gom_uri_set_property;
+ oclass->dispose = gom_uri_dispose;
+
+ g_object_class_install_property (
+ oclass, PROP_URI,
+ g_param_spec_string ("uri", NULL,
+ "The URI this object represents.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ oclass, PROP_SCHEME,
+ g_param_spec_string ("scheme", NULL,
+ "URL scheme specifier.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ oclass, PROP_NETLOC,
+ g_param_spec_string ("netloc", NULL,
+ "Network location part.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ oclass, PROP_PATH,
+ g_param_spec_string ("path", NULL,
+ "Hierarchical path.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ oclass, PROP_QUERY,
+ g_param_spec_string ("query", NULL,
+ "Query component.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ oclass, PROP_FRAGMENT,
+ g_param_spec_string ("fragment", NULL,
+ "Fragment identifier.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ oclass, PROP_USERNAME,
+ g_param_spec_string ("username", NULL,
+ "User name.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ oclass, PROP_PASSWORD,
+ g_param_spec_string ("password", NULL,
+ "Password.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ oclass, PROP_HOSTNAME,
+ g_param_spec_string ("hostname", NULL,
+ "Host name (lower case).",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ oclass, PROP_PORT,
+ g_param_spec_int ("port", NULL,
+ "Port number as integer, if present.",
+ G_MININT, G_MAXINT, 0,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}

Modified: trunk/gom/src/libgom/gomxhr.c
==============================================================================
--- trunk/gom/src/libgom/gomxhr.c (original)
+++ trunk/gom/src/libgom/gomxhr.c Sat Jul 26 12:43:10 2008
@@ -29,11 +29,16 @@

#include "gom/dom/gomeventtarget.h"
#include "gom/dom/gomdomexception.h"
+#include "gom/gomuri.h"

#include "gommacros.h"

+#include <string.h>
+#include <curl/curl.h>
+
enum {
- PROP_ONREADYSTATECHANGE = 1,
+ PROP_DOCUMENT = 1,
+ PROP_ONREADYSTATECHANGE,
PROP_READY_STATE,
PROP_RESPONSE_TEXT,
PROP_RESPONSE_XML,
@@ -42,16 +47,25 @@
};

typedef struct {
- char f;
+ GomDocument *doc;
+
+ GSList *reqhdr_names;
+ GSList *reqhdr_values;
+
+ GomURI *uri;
+
+ GomXMLHttpRequestState state;
+
+ gboolean send : 1;
} GomXhrPrivate;

#define PRIV(i) G_TYPE_INSTANCE_GET_PRIVATE ((i), GOM_TYPE_XHR, GomXhrPrivate)

static void
gom_xhr_get_property (GObject *object,
- guint property_id,
- GValue *value,
- GParamSpec *pspec)
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
{
GomXhrPrivate *priv = PRIV (object);

@@ -59,6 +73,7 @@
case PROP_ONREADYSTATECHANGE:
break;
case PROP_READY_STATE:
+ g_value_set_enum (value, priv->state);
break;
case PROP_RESPONSE_TEXT:
break;
@@ -76,13 +91,16 @@

static void
gom_xhr_set_property (GObject *object,
- guint property_id,
- const GValue *value,
- GParamSpec *pspec)
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
GomXhrPrivate *priv = PRIV (object);

switch (property_id) {
+ case PROP_DOCUMENT:
+ GOM_SET_WEAK (priv->doc, g_value_get_object (value));
+ break;
case PROP_ONREADYSTATECHANGE:
break;
default:
@@ -99,6 +117,54 @@

#define gom_xhr_dispatch_listeners gom_evt_tgt_dispatch_listeners

+#define TOK_SEPARATORS "()<>@,;:\"/[]?={} \t"
+
+/*
+ CTL = <any US-ASCII control character
+ (octets 0 - 31) and DEL (127)>
+ SP = <US-ASCII SP, space (32)>
+ HT = <US-ASCII HT, horizontal-tab (9)>
+ token = 1*<any CHAR except CTLs or separators>
+ separators = "(" | ")" | "<" | ">" | "@"
+ | "," | ";" | ":" | "\" | <">
+ | "/" | "[" | "]" | "?" | "="
+ | "{" | "}" | SP | HT
+*/
+static gboolean
+is_token (const char *s)
+{
+ gunichar c;
+ while (*s) {
+ c = g_utf8_get_char (s);
+ if (c < 32 || c >= 127 || strchr (TOK_SEPARATORS, c)) {
+ return FALSE;
+ }
+ s = g_utf8_next_char (s);
+ }
+ return TRUE;
+}
+
+const char *matched_methods[] = {
+ "CONNECT",
+ "DELETE",
+ "GET",
+ "HEAD",
+ "OPTIONS",
+ "POST",
+ "PUT",
+ "TRACE",
+ "TRACK",
+ NULL
+};
+
+const char *disallowed_methods[] = {
+ "CONNECT",
+ "TRACE",
+ "TRACK",
+ NULL
+};
+
+/* http://www.w3.org/TR/XMLHttpRequest/#open */
static void
gom_xhr_open (GomXMLHttpRequest *xml_http_request,
const char *method,
@@ -107,10 +173,344 @@
const char *user,
const char *password,
GError **error)
-{GomXhrPrivate *priv = PRIV (xml_http_request);
- GOM_NOT_IMPLEMENTED_ERROR (error);
+{
+ GomXhrPrivate *priv = PRIV (xml_http_request);
+ const char **s;
+ GomURI *uri;
+ char *scheme;
+ const curl_version_info_data *curl_data;
+ const char * const*protocol;
+
+ /* 1. Let stored method be the method argument. */
+
+ /*
+ * 2. If stored method does not match the Method production,
+ * defined in section 5.1.1 of RFC 2616, raise a SYNTAX_ERR
+ * exception and terminate these steps. [RFC2616]
+ */
+ if (!method || !is_token (method)) {
+ g_set_error (error, GOM_DOM_EXCEPTION_ERROR,
GOM_SYNTAX_ERR, "method is not a valid token");
+ return;
+ }
+
+ /*
+ * 3. If stored method case-insensitively matches CONNECT, DELETE,
+ * GET, HEAD, OPTIONS POST, PUT, TRACE, or TRACK let stored method
+ * be the canonical uppercase form of the matched method name.
+ */
+ for (s = matched_methods; *s; s++) {
+ if (!strcasecmp (method, *s)) {
+ method = *s;
+ break;
+ }
+ }
+
+ /*
+ * 4. If stored method is one of CONNECT, TRACE, or TRACK the user
+ * agent should raise a SECURITY_ERR exception and terminate these
+ * steps.
+ */
+ for (s = disallowed_methods; *s; s++) {
+ if (!strcasecmp (method, *s)) {
+ g_set_error (error, GOM_DOM_EXCEPTION_ERROR, GOM_SECURITY_ERR,
+ "disallowed method specified");
+ return;
+ }
+ }
+
+ /*
+ * 5. Drop the fragment identifier (if any) from url and let
+ * stored url be the result of that operation.
+ */
+ uri = g_object_new (GOM_TYPE_URI,
+ "uri", url,
+ "fragment", NULL,
+ NULL);
+
+ /*
+ * 6. If stored url is a relative reference resolve it using the
+ * current value of the baseURI attribute of the Document
+ * pointer. If this fails raise a SYNTAX_ERR exception and
+ * terminate these steps.
+ */
+ if (gom_uri_is_relative (uri)) {
+ char *new_uri = NULL;
+ if (priv->doc) {
+ char *base_uri;
+ g_object_get (priv->doc, "document-u-r-i", &base_uri, NULL);
+ if (base_uri && *base_uri) {
+ char *rel_uri;
+ g_object_get (uri, "uri", &rel_uri, NULL);
+ new_uri = gom_uri_join (base_uri, rel_uri);
+ g_free (rel_uri);
+ }
+ g_free (base_uri);
+ }
+ g_object_unref (uri);
+ if (!new_uri) {
+ g_set_error (error, GOM_DOM_EXCEPTION_ERROR, GOM_SYNTAX_ERR,
+ "could not resolve relative uri");
+ return;
+ }
+ uri = g_object_new (GOM_TYPE_URI, "uri", new_uri, NULL);
+ }
+
+ /*
+ * 7. If stored url contains an unsupported scheme raise a
+ * NOT_SUPPORTED_ERR and terminate these steps.
+ */
+ g_object_get (uri, "scheme", &scheme, NULL);
+ curl_data = curl_version_info (CURLVERSION_NOW);
+ for (protocol = curl_data->protocols; *protocol; protocol++) {
+ if (!strcmp (scheme, *protocol)) {
+ break;
+ }
+ }
+ g_free (scheme);
+ if (!*protocol) {
+ g_object_unref (uri);
+ g_set_error (error, GOM_DOM_EXCEPTION_ERROR, GOM_NOT_SUPPORTED_ERR,
+ "scheme not supported by cURL");
+ return;
+ }
+
+ /*
+ * 8. If the "user:password" format in the userinfo production
+ * defined in section 3.2.1 of RFC 3986 is not supported for the
+ * relevant scheme and stored url contains this format raise a
+ * SYNTAX_ERR and terminate these steps. [RFC3986]
+ */
+
+ /*
+ * 9. If stored url contains the "user:password" format let stored
+ * user be the user part and stored password be the password part.
+ */
+
+ /*
+ * 10. If stored url just contains the "user" format let stored
+ * user be the user part.
+ */
+
+ /*
+ * 11. If stored url is not of the same-origin as the origin of
+ * the Document pointer the user agent should raise a SECURITY_ERR
+ * exception and terminate these steps.
+ */
+
+ /*
+ * 12. Let async be the value of the async argument or true if it
+ * was omitted.
+ */
+
+ /*
+ * 13. If the user argument was not omitted, and its syntax does
+ * not match that specified by the relevant authentication scheme,
+ * raise a SYNTAX_ERR exception and terminate these steps.
+ */
+ /*
+ * 14. If the user argument was not omitted and is not null let
+ * stored user be user encoded using the encoding specified in the
+ * relevant authentication scheme or UTF-8 if the scheme fails to
+ * specify an encoding.
+ */
+ /*
+ * 15. If the user argument was not omitted and is null remove
+ * stored user.
+ */
+ if (user != GOM_XML_HTTP_REQUEST_OMITTED) {
+ g_object_set (uri, "user", user, NULL);
+ }
+
+ /*
+ * 16.If the password argument was not omitted and its syntax does
+ * not match that specified by the relevant authentication scheme
+ * raise a SYNTAX_ERR exception and terminate these steps.
+ */
+ /*
+ * 17. If the password argument was not omitted and is not null
+ * let stored password be password encoded using the encoding
+ * specified in the relevant authentication scheme or UTF-8 if the
+ * scheme fails to specify an encoding.
+ */
+ /*
+ * 18. If the password argument was not omitted and is null remove
+ * stored password.
+ */
+ if (password != GOM_XML_HTTP_REQUEST_OMITTED) {
+ g_object_set (uri, "password", password, NULL);
+ }
+
+ /*
+ * 19. Abort the send() algorithm, set response entity body to
+ * "null" and reset the list of request headers.
+ */
+ g_slist_foreach (priv->reqhdr_names, (GFunc)g_free, NULL);
+ g_slist_free (priv->reqhdr_names);
+ priv->reqhdr_names = NULL;
+
+ g_slist_foreach (priv->reqhdr_values, (GFunc)g_free, NULL);
+ g_slist_free (priv->reqhdr_values);
+ priv->reqhdr_values = NULL;
+ /*
+ * 20. The user agent should cancel any network activity for which
+ * the object is responsible.
+ */
+ /*
+ * 21. Switch the object to the OPENED state, set the send() flag
+ * to "false" and then synchronously dispatch a readystatechange
+ * event on the object and return the method call.
+ */
+ priv->state = GOM_OPENED;
+ priv->send = FALSE;
+ if (priv->uri) {
+ g_object_unref (priv->uri);
+ }
+ priv->uri = uri;
+}
+
+/*
+ CR = <US-ASCII CR, carriage return (13)>
+ LF = <US-ASCII LF, linefeed (10)>
+ LWS = [CRLF] 1*( SP | HT )
+*/
+static gboolean
+is_lws (const char **s)
+{
+ gunichar c;
+
+ g_assert (g_utf8_get_char (*s) == '\r');
+
+ *s = g_utf8_next_char (*s);
+ c = g_utf8_get_char (*s);
+ if (c != '\n') {
+ return FALSE;
+ }
+ *s = g_utf8_next_char (*s);
+ c = g_utf8_get_char (*s);
+ if (c != '\t' && c != ' ') {
+ return FALSE;
+ }
+ /* this is valid LWS; eat the rest of leading ws */
+ while (**s) {
+ c = g_utf8_get_char (*s);
+ if (c != '\t' && c != ' ') {
+ break;
+ }
+ *s = g_utf8_next_char (*s);
+ }
+ return TRUE;
+}
+
+/*
+ quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
+ CHAR = <any US-ASCII character (octets 0 - 127)>
+ quoted-pair = "\" CHAR
+ qdtext = <any TEXT except <">>
+*/
+static gboolean
+is_quoted_string (const char **s)
+{
+ gunichar c;
+
+ g_assert (g_utf8_get_char (*s) == '"');
+
+ while (**s) {
+ c = g_utf8_get_char (*s);
+ switch (c) {
+ case '"':
+ return TRUE;
+ case '\r':
+ if (is_lws (s)) {
+ continue;
+ } else {
+ return FALSE;
+ }
+ g_assert_not_reached ();
+ case '\\':
+ *s = g_utf8_next_char (*s);
+ if (g_utf8_get_char (*s) >= 128) {
+ return FALSE;
+ }
+ break;
+ default:
+ if (c < 32 || c >= 127) {
+ return FALSE;
+ }
+ break;
+ }
+ *s = g_utf8_next_char (*s);
+ }
+ return FALSE;
+}
+
+/*
+ TEXT = <any OCTET except CTLs,
+ but including LWS>
+ field-value = *( field-content | LWS )
+ field-content = <the OCTETs making up the field-value
+ and consisting of either *TEXT or combinations
+ of token, separators, and quoted-string>
+*/
+static gboolean
+is_value (const char *s)
+{
+ gunichar c;
+
+ while (*s) {
+ c = g_utf8_get_char (s);
+ switch (c) {
+ case '\r':
+ if (is_lws (&s)) {
+ /* don't read next char; is_lws() already read it */
+ continue;
+ } else {
+ return FALSE;
+ }
+ break;
+ case '\t':
+ break;
+ case '"':
+ /* is_quoted_string() stops at " */
+ if (!is_quoted_string (&s)) {
+ return FALSE;
+ }
+ break;
+ default:
+ if (c < 32 || c >= 127) {
+ return FALSE;
+ }
+ break;
+ }
+ s = g_utf8_next_char (s);
+ }
+ return TRUE;
}

+static const char *disallowed_headers[] = {
+ "Accept-Charset",
+ "Accept-Encoding",
+ "Connection",
+ "Content-Length",
+ "Content-Transfer-Encoding",
+ "Date",
+ "Expect",
+ "Host",
+ "Keep-Alive",
+ "Referer",
+ "TE",
+ "Trailer",
+ "Transfer-Encoding",
+ "Upgrade",
+ "Via",
+ NULL
+};
+
+static const char *disallowed_prefixes[] = {
+ "Proxy-",
+ "Sec-",
+ NULL
+};
+
static void
gom_xhr_set_request_header (GomXMLHttpRequest *xml_http_request,
const char *header,
@@ -118,7 +518,42 @@
GError **error)
{
GomXhrPrivate *priv = PRIV (xml_http_request);
- GOM_NOT_IMPLEMENTED_ERROR (error);
+ const char **s;
+ if (priv->state != GOM_OPENED) {
+ g_set_error (error, GOM_DOM_EXCEPTION_ERROR, GOM_INVALID_STATE_ERR,
+ "request state is not OPENED");
+ return;
+ }
+ if (priv->send) {
+ g_set_error (error, GOM_DOM_EXCEPTION_ERROR, GOM_INVALID_STATE_ERR,
+ "request has already been sent");
+ return;
+ }
+ if (!header || !is_token (header)) {
+ g_set_error (error, GOM_DOM_EXCEPTION_ERROR, GOM_SYNTAX_ERR,
+ "invalid header");
+ return;
+ }
+ if (!value) {
+ return;
+ }
+ if (!is_value (value)) {
+ g_set_error (error, GOM_DOM_EXCEPTION_ERROR, GOM_SYNTAX_ERR,
+ "invalid value");
+ return;
+ }
+ for (s = disallowed_headers; *s; s++) {
+ if (!strcasecmp (header, *s)) {
+ return;
+ }
+ }
+ for (s = disallowed_prefixes; *s; s++) {
+ if (!strncasecmp (header, *s, strlen (*s))) {
+ return;
+ }
+ }
+ priv->reqhdr_names = g_slist_prepend (priv->reqhdr_names,
g_strdup (header));
+ priv->reqhdr_values = g_slist_prepend (priv->reqhdr_values,
g_strdup (value));
}

static void
@@ -202,6 +637,13 @@
oclass->dispose = gom_xhr_dispose;
oclass->get_property = gom_xhr_get_property;
oclass->set_property = gom_xhr_set_property;
+
+ g_object_class_install_property (
+ oclass, PROP_DOCUMENT,
+ g_param_spec_object ("document", NULL,
+ "The owning document, if any.",
+ GOM_TYPE_DOCUMENT,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE
| G_PARAM_STATIC_STRINGS));

g_object_class_override_property (oclass, PROP_ONREADYSTATECHANGE, "onreadystatechange");
g_object_class_override_property (oclass, PROP_READY_STATE, "ready-state");

Reply all
Reply to author
Forward
0 new messages